personalization: fix SdKey.apply_val() implementation
'securityDomain' elements are decoded to ProfileElementSD instances, which keep higher level representations of the key data apart from the decoded[] lists. So far, apply_val() was dropping binary values in decoded[], which does not work, because ProfileElementSD._pre_encode() overwrites self.decoded[] from the higher level representation. Implement using - ProfileElementSD.find_key() and SecurityDomainKeyComponent to modify an exsiting entry, or - ProfileElementSD.add_key() to create a new entry. Before this patch, SdKey parameters seemed to patch PES successfully, but their modifications did not end up in the encoded DER. (BTW, this does not fix any other errors that may still be present in the various SdKey subclasses, patches coming up.) Related: SYS#6768 Change-Id: I07dfc378705eba1318e9e8652796cbde106c6a52
This commit is contained in:
@@ -1071,6 +1071,13 @@ class SecurityDomainKey:
|
|||||||
'keyVersionNumber': bytes([self.key_version_number]),
|
'keyVersionNumber': bytes([self.key_version_number]),
|
||||||
'keyComponents': [k.to_saip_dict() for k in self.key_components]}
|
'keyComponents': [k.to_saip_dict() for k in self.key_components]}
|
||||||
|
|
||||||
|
def get_key_component(self, key_type):
|
||||||
|
for kc in self.key_components:
|
||||||
|
if kc.key_type == key_type:
|
||||||
|
return kc.key_data
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class ProfileElementSD(ProfileElement):
|
class ProfileElementSD(ProfileElement):
|
||||||
"""Class representing a securityDomain ProfileElement."""
|
"""Class representing a securityDomain ProfileElement."""
|
||||||
type = 'securityDomain'
|
type = 'securityDomain'
|
||||||
|
|||||||
@@ -24,9 +24,11 @@ from typing import List, Tuple, Generator, Optional
|
|||||||
from osmocom.tlv import camel_to_snake
|
from osmocom.tlv import camel_to_snake
|
||||||
from osmocom.utils import hexstr
|
from osmocom.utils import hexstr
|
||||||
from pySim.utils import enc_iccid, dec_iccid, enc_imsi, dec_imsi, h2b, b2h, rpad, sanitize_iccid
|
from pySim.utils import enc_iccid, dec_iccid, enc_imsi, dec_imsi, h2b, b2h, rpad, sanitize_iccid
|
||||||
from pySim.esim.saip import ProfileElement, ProfileElementSequence
|
|
||||||
from pySim.esim.saip import param_source
|
|
||||||
from pySim.ts_51_011 import EF_SMSP
|
from pySim.ts_51_011 import EF_SMSP
|
||||||
|
from pySim.esim.saip import param_source
|
||||||
|
from pySim.esim.saip import ProfileElement, ProfileElementSD, ProfileElementSequence
|
||||||
|
from pySim.esim.saip import SecurityDomainKey, SecurityDomainKeyComponent
|
||||||
|
from pySim.global_platform import KeyUsageQualifier, KeyType
|
||||||
|
|
||||||
def unrpad(s: hexstr, c='f') -> hexstr:
|
def unrpad(s: hexstr, c='f') -> hexstr:
|
||||||
return hexstr(s.rstrip(c))
|
return hexstr(s.rstrip(c))
|
||||||
@@ -591,36 +593,40 @@ class SdKey(BinaryParam, metaclass=ClassVarMeta):
|
|||||||
key_usage_qual = None
|
key_usage_qual = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _apply_sd(cls, pe: ProfileElement, value):
|
def apply_val(cls, pes: ProfileElementSequence, val):
|
||||||
assert pe.type == 'securityDomain'
|
set_components = [ SecurityDomainKeyComponent(cls.key_type, val) ]
|
||||||
for key in pe.decoded['keyList']:
|
|
||||||
if key['keyIdentifier'][0] == cls.key_id and key['keyVersionNumber'][0] == cls.kvn:
|
|
||||||
assert len(key['keyComponents']) == 1
|
|
||||||
key['keyComponents'][0]['keyData'] = value
|
|
||||||
return
|
|
||||||
# Could not find matching key to patch, create a new one
|
|
||||||
key = {
|
|
||||||
'keyUsageQualifier': bytes([cls.key_usage_qual]),
|
|
||||||
'keyIdentifier': bytes([cls.key_id]),
|
|
||||||
'keyVersionNumber': bytes([cls.kvn]),
|
|
||||||
'keyComponents': [
|
|
||||||
{ 'keyType': bytes([cls.key_type]), 'keyData': value },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
pe.decoded['keyList'].append(key)
|
|
||||||
|
|
||||||
@classmethod
|
for pe in pes.pe_list:
|
||||||
def apply_val(cls, pes: ProfileElementSequence, value):
|
if pe.type != 'securityDomain':
|
||||||
for pe in pes.get_pes_for_type('securityDomain'):
|
continue
|
||||||
cls._apply_sd(pe, value)
|
assert isinstance(pe, ProfileElementSD)
|
||||||
|
|
||||||
|
key = pe.find_key(key_version_number=cls.kvn, key_id=cls.key_id)
|
||||||
|
if not key:
|
||||||
|
# Could not find matching key to patch, create a new one
|
||||||
|
key = SecurityDomainKey(
|
||||||
|
key_version_number=cls.kvn,
|
||||||
|
key_id=cls.key_id,
|
||||||
|
key_usage_qualifier=KeyUsageQualifier.build(cls.key_usage_qual),
|
||||||
|
key_components=set_components,
|
||||||
|
)
|
||||||
|
pe.add_key(key)
|
||||||
|
else:
|
||||||
|
key.key_components = set_components
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_values_from_pes(cls, pes: ProfileElementSequence):
|
def get_values_from_pes(cls, pes: ProfileElementSequence):
|
||||||
for pe in pes.get_pes_for_type('securityDomain'):
|
for pe in pes.pe_list:
|
||||||
for key in pe.decoded['keyList']:
|
if pe.type != 'securityDomain':
|
||||||
if key['keyIdentifier'][0] == cls.key_id and key['keyVersionNumber'][0] == cls.kvn:
|
continue
|
||||||
if len(key['keyComponents']) >= 1:
|
assert isinstance(pe, ProfileElementSD)
|
||||||
yield { cls.name: b2h(key['keyComponents'][0]['keyData']) }
|
|
||||||
|
key = pe.find_key(key_version_number=cls.kvn, key_id=cls.key_id)
|
||||||
|
if not key:
|
||||||
|
continue
|
||||||
|
kc = key.get_key_component(cls.key_type)
|
||||||
|
if kc:
|
||||||
|
yield { cls.name: b2h(kc) }
|
||||||
|
|
||||||
class SdKeyScp80_01(SdKey, kvn=0x01, key_type=0x88, permitted_len=[16,24,32]): # AES key type
|
class SdKeyScp80_01(SdKey, kvn=0x01, key_type=0x88, permitted_len=[16,24,32]): # AES key type
|
||||||
pass
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user