[3/6] personalization: refactor Puk

Implement abstract DecimalHexParam, and use it to refactor Puk1 and Puk2
to the new ConfigurableParameter implementation style.

DecimalHexParam will also be used for Pin and Adm soon.

Change-Id: I271e6c030c890778ab7af9ab3bc7997e22018f6a
This commit is contained in:
Neels Hofmeyr
2025-03-01 01:28:23 +01:00
parent 22da7b1a96
commit d638757af2

View File

@@ -224,6 +224,27 @@ class DecimalParam(ConfigurableParameter):
return super().validate_val(val)
class DecimalHexParam(DecimalParam):
"""The input value is decimal digits. The decimal value is stored such that each hexadecimal digit represents one
decimal digit, useful for various PIN type parameters.
Optionally, the value is stored with padding, for example: rpad = 8 would store '123' as '123fffff'. This is also
common in PIN type parameters.
"""
rpad = None
rpad_char = 'f'
@classmethod
def validate_val(cls, val):
val = super().validate_val(val)
val = ''.join('%02x' % ord(x) for x in val)
if cls.rpad is not None:
c = cls.rpad_char
val = rpad(val, cls.rpad, c)
# a DecimalHexParam subclass expects the apply_val() input to be a bytes instance ready for the pes
return h2b(val)
class Iccid(DecimalParam):
"""ICCID Parameter. Input: string of decimal digits.
If the string of digits is only 18 digits long, add a Luhn check digit."""
@@ -412,28 +433,24 @@ 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):
"""Configurable PUK (Pin Unblock Code). String ASCII-encoded digits."""
keyReference = None
def validate(self):
if isinstance(self.input_value, int):
self.value = '%08d' % self.input_value
else:
self.value = self.input_value
# FIXME: valid length?
if not self.value.isdecimal():
raise ValueError('PUK must only contain decimal digits')
def apply(self, pes: ProfileElementSequence):
puk = ''.join(['%02x' % (ord(x)) for x in self.value])
padded_puk = rpad(puk, 16)
class Puk(DecimalHexParam):
"""Configurable PUK (Pin Unblock Code). String ASCII-encoded digits."""
allow_len = 8
rpad = 16
keyReference = None
@classmethod
def apply_val(cls, pes: ProfileElementSequence, val):
val_bytes = val
mf_pes = pes.pes_by_naa['mf'][0]
pukCodes = obtain_singleton_pe_from_pelist(mf_pes, 'pukCodes')
for pukCode in pukCodes.decoded['pukCodes']:
if pukCode['keyReference'] == self.keyReference:
pukCode['pukValue'] = h2b(padded_puk)
if pukCode['keyReference'] == cls.keyReference:
pukCode['pukValue'] = val_bytes
return
raise ValueError('cannot find pukCode')
raise ValueError("input template UPP has unexpected structure:"
f" cannot find pukCode with keyReference={cls.keyReference}")
class Puk1(Puk):
keyReference = 0x01
@@ -441,6 +458,7 @@ class Puk1(Puk):
class Puk2(Puk):
keyReference = 0x81
class Pin(ConfigurableParameter):
"""Configurable PIN (Personal Identification Number). String of digits."""
keyReference = None