[1/6] personalization: refactor: drop ClassVarMeta use

Drop the ClassVarMeta/metaclass/ABCMeta stuff -- it doesn't seem to
serve any purpose that is not similarly achieved with plain python
inheritance.

Upcoming patches will use normal inheritance a lot more.

Note that most use of the ClassVarMeta was in the SdKey subclasses, and
that these currently don't actually work. See the fix in patch
I07dfc378705eba1318e9e8652796cbde106c6a52 .

name: set a default name from the python class, as ClassVarMeta did.
Also allow setting an explicit string as name instead, per subclass
implementation (see I31f390d634e58c384589c50a33ca45d6f86d4e10).

Related: SYS#6768
Change-Id: I60ea8fd11fb438ec90ddb08b17b658cbb789c051
This commit is contained in:
Neels Hofmeyr
2025-03-01 00:53:15 +01:00
parent 572a81f2af
commit 8e6a19d9f0

View File

@@ -34,24 +34,34 @@ def file_replace_content(file: List[Tuple], new_content: bytes):
file.append(('fillFileContent', new_content))
return file
class ClassVarMeta(abc.ABCMeta):
"""Metaclass that puts all additional keyword-args into the class. We use this to have one
class definition for something like a PIN, and then have derived classes for PIN1, PIN2, ..."""
def __new__(metacls, name, bases, namespace, **kwargs):
#print("Meta_new_(metacls=%s, name=%s, bases=%s, namespace=%s, kwargs=%s)" % (metacls, name, bases, namespace, kwargs))
x = super().__new__(metacls, name, bases, namespace)
for k, v in kwargs.items():
setattr(x, k, v)
setattr(x, 'name', camel_to_snake(name))
return x
class ConfigurableParameter(abc.ABC, metaclass=ClassVarMeta):
class ConfigurableParameter:
"""Base class representing a part of the eSIM profile that is configurable during the
personalization process (with dynamic data from elsewhere)."""
# A subclass can set an explicit string as name (like name = "PIN1").
# If name is left None, then __init__() will set self.name to a name derived from the python class name (like
# "pin1"). See also the get_name() classmethod when you have no instance at hand.
name = None
def __init__(self, input_value):
self.input_value = input_value # the raw input value as given by caller
self.value = None # the processed input value (e.g. with check digit) as produced by validate()
# set the instance's name to either an explicit name string, or to a name derived from the class name.
if self.name is None:
self.name = self.get_name()
@classmethod
def get_name(cls):
"""Return cls.name when it is set, otherwise return the python class name converted from 'CamelCase' to
'snake_case'.
When using class *instances*, you can just use my_instance.name.
When using *classes*, cls.get_name() returns the same name a class instance would have.
"""
if cls.name:
return cls.name
return camel_to_snake(cls.__name__)
def validate(self):
"""Optional validation method. Can be used by derived classes to perform validation
of the input value (self.value). Will raise an exception if validation fails."""
@@ -105,7 +115,7 @@ class Imsi(ConfigurableParameter):
# TODO: DF.GSM_ACCESS if not linked?
class SdKey(ConfigurableParameter, metaclass=ClassVarMeta):
class SdKey(ConfigurableParameter):
"""Configurable Security Domain (SD) Key. Value is presented as bytes."""
# these will be set by derived classes
key_type = None
@@ -144,59 +154,108 @@ class SdKey(ConfigurableParameter, metaclass=ClassVarMeta):
for pe in pes.get_pes_for_type('securityDomain'):
self._apply_sd(pe)
class SdKeyScp80_01(SdKey, kvn=0x01, key_type=0x88, permitted_len=[16,24,32]): # AES key type
pass
class SdKeyScp80_01Kic(SdKeyScp80_01, key_id=0x01, key_usage_qual=0x18): # FIXME: ordering?
pass
class SdKeyScp80_01Kid(SdKeyScp80_01, key_id=0x02, key_usage_qual=0x14):
pass
class SdKeyScp80_01Kik(SdKeyScp80_01, key_id=0x03, key_usage_qual=0x48):
pass
class SdKeyScp80_01(SdKey):
kvn = 0x01
key_type = 0x88 # AES key type
allow_len = (16,24,32)
class SdKeyScp81_01(SdKey, kvn=0x81): # FIXME
pass
class SdKeyScp81_01Psk(SdKeyScp81_01, key_id=0x01, key_type=0x85, key_usage_qual=0x3C):
pass
class SdKeyScp81_01Dek(SdKeyScp81_01, key_id=0x02, key_type=0x88, key_usage_qual=0x48):
pass
class SdKeyScp80_01Kic(SdKeyScp80_01):
key_id = 0x01
key_usage_qual = 0x18 # FIXME: ordering?
class SdKeyScp02_20(SdKey, kvn=0x20, key_type=0x88, permitted_len=[16,24,32]): # AES key type
pass
class SdKeyScp02_20Enc(SdKeyScp02_20, key_id=0x01, key_usage_qual=0x18):
pass
class SdKeyScp02_20Mac(SdKeyScp02_20, key_id=0x02, key_usage_qual=0x14):
pass
class SdKeyScp02_20Dek(SdKeyScp02_20, key_id=0x03, key_usage_qual=0x48):
pass
class SdKeyScp80_01Kid(SdKeyScp80_01):
key_id = 0x02
key_usage_qual = 0x14
class SdKeyScp03_30(SdKey, kvn=0x30, key_type=0x88, permitted_len=[16,24,32]): # AES key type
pass
class SdKeyScp03_30Enc(SdKeyScp03_30, key_id=0x01, key_usage_qual=0x18):
pass
class SdKeyScp03_30Mac(SdKeyScp03_30, key_id=0x02, key_usage_qual=0x14):
pass
class SdKeyScp03_30Dek(SdKeyScp03_30, key_id=0x03, key_usage_qual=0x48):
pass
class SdKeyScp03_31(SdKey, kvn=0x31, key_type=0x88, permitted_len=[16,24,32]): # AES key type
pass
class SdKeyScp03_31Enc(SdKeyScp03_31, key_id=0x01, key_usage_qual=0x18):
pass
class SdKeyScp03_31Mac(SdKeyScp03_31, key_id=0x02, key_usage_qual=0x14):
pass
class SdKeyScp03_31Dek(SdKeyScp03_31, key_id=0x03, key_usage_qual=0x48):
pass
class SdKeyScp03_32(SdKey, kvn=0x32, key_type=0x88, permitted_len=[16,24,32]): # AES key type
pass
class SdKeyScp03_32Enc(SdKeyScp03_32, key_id=0x01, key_usage_qual=0x18):
pass
class SdKeyScp03_32Mac(SdKeyScp03_32, key_id=0x02, key_usage_qual=0x14):
pass
class SdKeyScp03_32Dek(SdKeyScp03_32, key_id=0x03, key_usage_qual=0x48):
pass
class SdKeyScp80_01Kik(SdKeyScp80_01):
key_id = 0x03
key_usage_qual = 0x48
class SdKeyScp81_01(SdKey):
kvn = 0x81 # FIXME
class SdKeyScp81_01Psk(SdKeyScp81_01):
key_id = 0x01
key_type = 0x85
key_usage_qual = 0x3C
class SdKeyScp81_01Dek(SdKeyScp81_01):
key_id = 0x02
key_type = 0x88
key_usage_qual = 0x48
class SdKeyScp02_20(SdKey):
kvn = 0x20
key_type = 0x88 # AES key type
allow_len = (16,24,32)
class SdKeyScp02_20Enc(SdKeyScp02_20):
key_id = 0x01
key_usage_qual = 0x18
class SdKeyScp02_20Mac(SdKeyScp02_20):
key_id = 0x02
key_usage_qual = 0x14
class SdKeyScp02_20Dek(SdKeyScp02_20):
key_id = 0x03
key_usage_qual = 0x48
class SdKeyScp03_30(SdKey):
kvn = 0x30
key_type = 0x88 # AES key type
allow_len = (16,24,32)
class SdKeyScp03_30Enc(SdKeyScp03_30):
key_id = 0x01
key_usage_qual = 0x18
class SdKeyScp03_30Mac(SdKeyScp03_30):
key_id = 0x02
key_usage_qual = 0x14
class SdKeyScp03_30Dek(SdKeyScp03_30):
key_id = 0x03
key_usage_qual = 0x48
class SdKeyScp03_31(SdKey):
kvn = 0x31
key_type = 0x88 # AES key type
allow_len = (16,24,32)
class SdKeyScp03_31Enc(SdKeyScp03_31):
key_id = 0x01
key_usage_qual = 0x18
class SdKeyScp03_31Mac(SdKeyScp03_31):
key_id = 0x02
key_usage_qual = 0x14
class SdKeyScp03_31Dek(SdKeyScp03_31):
key_id = 0x03
key_usage_qual = 0x48
class SdKeyScp03_32(SdKey):
kvn = 0x32
key_type = 0x88 # AES key type
allow_len = (16,24,32)
class SdKeyScp03_32Enc(SdKeyScp03_32):
key_id = 0x01
key_usage_qual = 0x18
class SdKeyScp03_32Mac(SdKeyScp03_32):
key_id = 0x02
key_usage_qual = 0x14
class SdKeyScp03_32Dek(SdKeyScp03_32):
key_id = 0x03
key_usage_qual = 0x48
def obtain_singleton_pe_from_pelist(l: List[ProfileElement], wanted_type: str) -> ProfileElement:
@@ -208,7 +267,7 @@ def obtain_first_pe_from_pelist(l: List[ProfileElement], wanted_type: str) -> Pr
filtered = list(filter(lambda x: x.type == wanted_type, l))
return filtered[0]
class Puk(ConfigurableParameter, metaclass=ClassVarMeta):
class Puk(ConfigurableParameter):
"""Configurable PUK (Pin Unblock Code). String ASCII-encoded digits."""
keyReference = None
def validate(self):
@@ -230,12 +289,14 @@ class Puk(ConfigurableParameter, metaclass=ClassVarMeta):
pukCode['pukValue'] = h2b(padded_puk)
return
raise ValueError('cannot find pukCode')
class Puk1(Puk, keyReference=0x01):
pass
class Puk2(Puk, keyReference=0x81):
pass
class Pin(ConfigurableParameter, metaclass=ClassVarMeta):
class Puk1(Puk):
keyReference = 0x01
class Puk2(Puk):
keyReference = 0x81
class Pin(ConfigurableParameter):
"""Configurable PIN (Personal Identification Number). String of digits."""
keyReference = None
def validate(self):
@@ -259,7 +320,8 @@ class Pin(ConfigurableParameter, metaclass=ClassVarMeta):
pinCode['pinValue'] = h2b(padded_pin)
return
raise ValueError('cannot find pinCode')
class AppPin(ConfigurableParameter, metaclass=ClassVarMeta):
class AppPin(ConfigurableParameter):
"""Configurable PIN (Personal Identification Number). String of digits."""
keyReference = None
def validate(self):
@@ -288,18 +350,21 @@ class AppPin(ConfigurableParameter, metaclass=ClassVarMeta):
continue
for instance in pes.pes_by_naa[naa]:
self._apply_one(instance)
class Pin1(Pin, keyReference=0x01):
pass
class Pin1(Pin):
keyReference = 0x01
# PIN2 is special: telecom + usim + isim + csim
class Pin2(AppPin, keyReference=0x81):
pass
class Adm1(Pin, keyReference=0x0A):
pass
class Adm2(Pin, keyReference=0x0B):
pass
class Pin2(AppPin):
keyReference = 0x81
class Adm1(Pin):
keyReference = 0x0A
class Adm2(Pin):
keyReference = 0x0B
class AlgoConfig(ConfigurableParameter, metaclass=ClassVarMeta):
class AlgoConfig(ConfigurableParameter):
"""Configurable Algorithm parameter."""
key = None
def validate(self):
@@ -313,11 +378,13 @@ class AlgoConfig(ConfigurableParameter, metaclass=ClassVarMeta):
continue
algoConfiguration[1][self.key] = self.value
class K(AlgoConfig, key='key'):
pass
class Opc(AlgoConfig, key='opc'):
pass
class AlgorithmID(AlgoConfig, key='algorithmID'):
class K(AlgoConfig):
key = 'key'
class Opc(AlgoConfig):
key = 'opc'
class AlgorithmID(AlgoConfig):
key = 'algorithmID'
def validate(self):
if self.input_value not in [1, 2, 3]:
raise ValueError('Invalid algorithmID %s' % (self.input_value))