blob: 45ebf1c33c3415cbc6c1564ebf46b66e959177b6 [file] [log] [blame]
Harald Welte268a2022023-10-22 13:12:11 +02001# -*- coding: utf-8 -*-
2
3"""
4Various definitions related to GSMA eSIM / eUICC
5
6Related Specs: GSMA SGP.22, GSMA SGP.02, etc.
7"""
8
9# Copyright (C) 2023 Harald Welte <laforge@osmocom.org>
10#
11# This program is free software: you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation, either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program. If not, see <http://www.gnu.org/licenses/>.
23
24from pySim.tlv import *
25from pySim.construct import *
26from construct import Optional as COptional
27from construct import *
28import argparse
29from cmd2 import cmd2, CommandSet, with_default_category
30from pySim.commands import SimCardCommands
31from pySim.filesystem import CardADF, CardApplication
32from pySim.utils import Hexstr, SwHexstr
33import pySim.global_platform
34
35class VersionAdapter(Adapter):
36 """convert an EUICC Version (3-int array) to a textual representation."""
37
38 def _decode(self, obj, context, path):
39 return "%u.%u.%u" % (obj[0], obj[1], obj[2])
40
41 def _encode(self, obj, context, path):
42 return [int(x) for x in obj.split('.')]
43
44VersionType = VersionAdapter(Array(3, Int8ub))
45
46# Application Identifiers as defined in GSMA SGP.02 Annex H
47AID_ISD_R = "A0000005591010FFFFFFFF8900000100"
48AID_ECASD = "A0000005591010FFFFFFFF8900000200"
49AID_ISD_P_FILE = "A0000005591010FFFFFFFF8900000D00"
50AID_ISD_P_MODULE = "A0000005591010FFFFFFFF8900000E00"
51
52sw_isdr = {
53 'ISD-R': {
54 '6a80': 'Incorrect values in command data',
55 '6a82': 'Profile not found',
56 '6a88': 'Reference data not found',
57 '6985': 'Conditions of use not satisfied',
58 }
59}
60
61class SupportedVersionNumber(BER_TLV_IE, tag=0x82):
62 _construct = GreedyBytes
63
64class IsdrProprietaryApplicationTemplate(BER_TLV_IE, tag=0xe0, nested=[SupportedVersionNumber]):
65 # FIXME: lpaeSupport - what kind of tag would it have?
66 pass
67
68# GlobalPlatform 2.1.1 Section 9.9.3.1 from pySim/global_platform.py extended with E0
69class FciTemplate(BER_TLV_IE, tag=0x6f, nested=pySim.global_platform.FciTemplateNestedList +
70 [IsdrProprietaryApplicationTemplate]):
71 pass
72
73
74# SGP.22 Section 5.7.3: GetEuiccConfiguredAddresses
75class DefaultDpAddress(BER_TLV_IE, tag=0x80):
76 _construct = Utf8Adapter(GreedyBytes)
77class RootDsAddress(BER_TLV_IE, tag=0x81):
78 _construct = Utf8Adapter(GreedyBytes)
79class EuiccConfiguredAddresses(BER_TLV_IE, tag=0xbf3c, nested=[DefaultDpAddress, RootDsAddress]):
80 pass
81
82# SGP.22 Section 5.7.4: SetDefaultDpAddress
83class SetDefaultDpAddrRes(BER_TLV_IE, tag=0x80):
84 _construct = Enum(Int8ub, ok=0, undefinedError=127)
85class SetDefaultDpAddress(BER_TLV_IE, tag=0xbf3f, nested=[DefaultDpAddress, SetDefaultDpAddrRes]):
86 pass
87
88# SGP.22 Section 5.7.7: GetEUICCChallenge
89class EuiccChallenge(BER_TLV_IE, tag=0x80):
90 _construct = HexAdapter(Bytes(16))
91class GetEuiccChallenge(BER_TLV_IE, tag=0xbf2e, nested=[EuiccChallenge]):
92 pass
93
94# SGP.22 Section 5.7.8: GetEUICCInfo
95class SVN(BER_TLV_IE, tag=0x82):
96 _construct = VersionType
97class SubjectKeyIdentifier(BER_TLV_IE, tag=0x81):
98 _construct = HexAdapter(GreedyBytes)
99class SubjectKeyIdentifierSeq(BER_TLV_IE, tag=0x04, nested=[SubjectKeyIdentifier]):
100 pass
101class EuiccCiPkiListForVerification(BER_TLV_IE, tag=0xa9, nested=[SubjectKeyIdentifierSeq]):
102 pass
103class EuiccCiPkiListForSigning(BER_TLV_IE, tag=0xaa, nested=[SubjectKeyIdentifierSeq]):
104 pass
105class EuiccInfo1(BER_TLV_IE, tag=0xbf20, nested=[SVN, EuiccCiPkiListForVerification, EuiccCiPkiListForSigning]):
106 pass
107class ProfileVersion(BER_TLV_IE, tag=0x81):
108 _construct = VersionType
109class EuiccFirmwareVer(BER_TLV_IE, tag=0x83):
110 _construct = VersionType
111class ExtCardResource(BER_TLV_IE, tag=0x84):
112 _construct = HexAdapter(GreedyBytes)
113class UiccCapability(BER_TLV_IE, tag=0x85):
114 _construct = HexAdapter(GreedyBytes) # FIXME
115class TS102241Version(BER_TLV_IE, tag=0x86):
116 _construct = VersionType
117class GlobalPlatformVersion(BER_TLV_IE, tag=0x87):
118 _construct = VersionType
119class RspCapability(BER_TLV_IE, tag=0x88):
120 _construct = HexAdapter(GreedyBytes) # FIXME
121class EuiccCategory(BER_TLV_IE, tag=0x8b):
122 _construct = Enum(Int8ub, other=0, basicEuicc=1, mediumEuicc=2, contactlessEuicc=3)
123class PpVersion(BER_TLV_IE, tag=0x04):
124 _construct = VersionType
125class SsAcreditationNumber(BER_TLV_IE, tag=0x0c):
126 _construct = Utf8Adapter(GreedyBytes)
127
128class EuiccInfo2(BER_TLV_IE, tag=0xbf22, nested=[ProfileVersion, SVN, EuiccFirmwareVer, ExtCardResource,
129 UiccCapability, TS102241Version, GlobalPlatformVersion,
130 RspCapability, EuiccCiPkiListForVerification,
131 EuiccCiPkiListForSigning, EuiccCategory, PpVersion,
132 SsAcreditationNumber]):
133 pass
134
135
136# SGP.22 Section 5.7.9: ListNotification
137class ProfileMgmtOperation(BER_TLV_IE, tag=0x81):
138 _construct = FlagsEnum(Byte, install=1, enable=2, disable=4, delete=8)
139class ListNotificationReq(BER_TLV_IE, tag=0xbf28, nested=[ProfileMgmtOperation]):
140 pass
141class SeqNumber(BER_TLV_IE, tag=0x80):
142 _construct = GreedyInteger
143class NotificationAddress(BER_TLV_IE, tag=0x82):
144 _construct = Utf8Adapter(GreedyBytes)
145class Iccid(BER_TLV_IE, tag=0x5a):
146 _construct = HexAdapter(GreedyBytes)
147class NotificationMetadata(BER_TLV_IE, tag=0xbf2f, nested=[SeqNumber, ProfileMgmtOperation,
148 NotificationAddress, Iccid]):
149 pass
150class NotificationMetadataList(BER_TLV_IE, tag=0xa0, nested=[NotificationMetadata]):
151 pass
152class ListNotificationsResultError(BER_TLV_IE, tag=0x81):
153 _construct = Enum(Int8ub, undefinedError=127)
154class ListNotificationResp(BER_TLV_IE, tag=0xbf28, nested=[NotificationMetadataList,
155 ListNotificationsResultError]):
156 pass
157
158# SGP.22 Section 5.7.11: RemoveNotificationFromList
159class DeleteNotificationStatus(BER_TLV_IE, tag=0x80):
160 _construct = Enum(Int8ub, ok=0, nothingToDelete=1, undefinedError=127)
161class NotificationSentReq(BER_TLV_IE, tag=0xbf30, nested=[SeqNumber]):
162 pass
163class NotificationSentResp(BER_TLV_IE, tag=0xbf30, nested=[DeleteNotificationStatus]):
164 pass
165
166# SGP.22 Section 5.7.12: LoadCRL: FIXME
167class LoadCRL(BER_TLV_IE, tag=0xbf35, nested=[]): # FIXME
168 pass
169
Harald Welte884eb552023-10-24 11:03:50 +0200170# SGP.22 Section 5.7.15: GetProfilesInfo
171class TagList(BER_TLV_IE, tag=0x5c):
172 _construct = GreedyRange(Int8ub) # FIXME: tags could be multi-byte
173class ProfileInfoListReq(BER_TLV_IE, tag=0xbf2d, nested=[TagList]): # FIXME: SearchCriteria
174 pass
175class IsdpAid(BER_TLV_IE, tag=0x4f):
176 _construct = HexAdapter(GreedyBytes)
177class ProfileState(BER_TLV_IE, tag=0x9f70):
178 _construct = Enum(Int8ub, disabled=0, enabled=1)
179class ProfileNickname(BER_TLV_IE, tag=0x90):
180 _construct = Utf8Adapter(GreedyBytes)
181class ServiceProviderName(BER_TLV_IE, tag=0x91):
182 _construct = Utf8Adapter(GreedyBytes)
183class ProfileName(BER_TLV_IE, tag=0x92):
184 _construct = Utf8Adapter(GreedyBytes)
185class IconType(BER_TLV_IE, tag=0x93):
186 _construct = Enum(Int8ub, jpg=0, png=1)
187class Icon(BER_TLV_IE, tag=0x94):
188 _construct = GreedyBytes
189class ProfileClass(BER_TLV_IE, tag=0x95):
190 _construct = Enum(Int8ub, test=0, provisioning=1, operational=2)
191class ProfileInfo(BER_TLV_IE, tag=0xe3, nested=[Iccid, IsdpAid, ProfileState, ProfileNickname,
192 ServiceProviderName, ProfileName, IconType, Icon,
193 ProfileClass]): # FIXME: more IEs
194 pass
195class ProfileInfoSeq(BER_TLV_IE, tag=0xa0, nested=[ProfileInfo]):
196 pass
197class ProfileInfoListError(BER_TLV_IE, tag=0x81):
198 _construct = Enum(Int8ub, incorrectInputValues=1, undefinedError=2)
199class ProfileInfoListResp(BER_TLV_IE, tag=0xbf2d, nested=[ProfileInfoSeq, ProfileInfoListError]):
200 pass
201
Harald Welte268a2022023-10-22 13:12:11 +0200202# SGP.22 Section 5.7.16:: EnableProfile
203class RefreshFlag(BER_TLV_IE, tag=0x88): # FIXME
204 _construct = Int8ub # FIXME
Harald Welte268a2022023-10-22 13:12:11 +0200205class EnableResult(BER_TLV_IE, tag=0x80):
206 _construct = Enum(Int8ub, ok=0, iccidOrAidNotFound=1, profileNotInDisabledState=2,
207 disallowedByPolicy=3, wrongProfileReenabling=4, catBusy=5, undefinedError=127)
208class EnableProfileReq(BER_TLV_IE, tag=0xbf31, nested=[IsdpAid, Iccid, RefreshFlag]):
209 pass
210class EnableProfileResp(BER_TLV_IE, tag=0xbf31, nested=[EnableResult]):
211 pass
212
213# SGP.22 Section 5.7.17 DisableProfile
214class DisableResult(BER_TLV_IE, tag=0x80):
215 _construct = Enum(Int8ub, ok=0, iccidOrAidNotFound=1, profileNotInEnabledState=2,
216 disallowedByPolicy=3, catBusy=5, undefinedError=127)
217class DisableProfileReq(BER_TLV_IE, tag=0xbf32, nested=[IsdpAid, Iccid, RefreshFlag]):
218 pass
219class DisableProfileResp(BER_TLV_IE, tag=0xbf32, nested=[DisableResult]):
220 pass
221
222# SGP.22 Section 5.7.18: DeleteProfile
223class DeleteResult(BER_TLV_IE, tag=0x80):
224 _construct = Enum(Int8ub, ok=0, iccidOrAidNotFound=1, profileNotInDisabledState=2,
225 disallowedByPolicy=3, undefinedError=127)
226class DeleteProfileReq(BER_TLV_IE, tag=0xbf33, nested=[IsdpAid, Iccid]):
227 pass
228class DeleteProfileResp(BER_TLV_IE, tag=0xbf33, nested=[DeleteResult]):
229 pass
230
231# SGP.22 Section 5.7.20 GetEID
Harald Welte268a2022023-10-22 13:12:11 +0200232class EidValue(BER_TLV_IE, tag=0x5a):
233 _construct = HexAdapter(GreedyBytes)
234class GetEuiccData(BER_TLV_IE, tag=0xbf3e, nested=[TagList, EidValue]):
235 pass
236
237# SGP.22 Section 5.7.21: ES10c SetNickname
Harald Welte884eb552023-10-24 11:03:50 +0200238class SnrProfileNickname(BER_TLV_IE, tag=0x8f):
Harald Welte268a2022023-10-22 13:12:11 +0200239 _construct = Utf8Adapter(GreedyBytes)
Harald Welte884eb552023-10-24 11:03:50 +0200240class SetNicknameReq(BER_TLV_IE, tag=0xbf29, children=[Iccid, SnrProfileNickname]):
Harald Welte268a2022023-10-22 13:12:11 +0200241 pass
242class SetNicknameResult(BER_TLV_IE, tag=0x80):
243 _construct = Enum(Int8ub, ok=0, iccidNotFound=1, undefinedError=127)
244class SetNicknameResp(BER_TLV_IE, tag=0xbf29, children=[SetNicknameResult]):
245 pass
246
247
248class ADF_ISDR(CardADF):
249 def __init__(self, aid=AID_ISD_R, name='ADF.ISD-R', fid=None, sfid=None,
250 desc='ISD-R (Issuer Security Domain Root) Application'):
251 super().__init__(aid=aid, fid=fid, sfid=sfid, name=name, desc=desc)
252 self.shell_commands += [self.AddlShellCommands()]
253
254 @staticmethod
255 def store_data(scc: SimCardCommands, tx_do: Hexstr) -> Tuple[Hexstr, SwHexstr]:
256 """Perform STORE DATA according to Table 47+48 in Section 5.7.2 of SGP.22.
257 Only single-block store supported for now."""
258 capdu = '%sE29100%02u%s' % (scc.cla4lchan('80'), len(tx_do)//2, tx_do)
259 return scc._tp.send_apdu_checksw(capdu)
260
261 @staticmethod
262 def store_data_tlv(scc: SimCardCommands, cmd_do, resp_cls, exp_sw='9000'):
263 """Transceive STORE DATA APDU with the card, transparently encoding the command data from TLV
264 and decoding the response data tlv."""
265 if cmd_do:
266 cmd_do_enc = cmd_do.to_tlv()
267 cmd_do_len = len(cmd_do_enc)
268 if cmd_do_len > 255:
269 return ValueError('DO > 255 bytes not supported yet')
270 else:
271 cmd_do_enc = b''
272 (data, sw) = ADF_ISDR.store_data(scc, b2h(cmd_do_enc))
273 if data:
274 if resp_cls:
275 resp_do = resp_cls()
276 resp_do.from_tlv(h2b(data))
277 return resp_do
278 else:
279 return data
280 else:
281 return None
282
283 def decode_select_response(self, data_hex: Hexstr) -> object:
284 t = FciTemplate()
285 t.from_tlv(h2b(data_hex))
286 d = t.to_dict()
287 return flatten_dict_lists(d['fci_template'])
288
289 @with_default_category('Application-Specific Commands')
290 class AddlShellCommands(CommandSet):
291
292 es10x_store_data_parser = argparse.ArgumentParser()
293 es10x_store_data_parser.add_argument('TX_DO', help='Hexstring of encoded to-be-transmitted DO')
294
295 @cmd2.with_argparser(es10x_store_data_parser)
296 def do_es10x_store_data(self, opts):
297 """Perform a raw STORE DATA command as defined for the ES10x eUICC interface."""
298 (data, sw) = ADF_ISDR.store_data(self._cmd.lchan.scc, opts.TX_DO)
299
300 def do_get_euicc_configured_addresses(self, opts):
301 """Perform an ES10a GetEuiccConfiguredAddresses function."""
302 eca = ADF_ISDR.store_data_tlv(self._cmd.lchan.scc, EuiccConfiguredAddresses(), EuiccConfiguredAddresses)
303 d = eca.to_dict()
304 self._cmd.poutput_json(flatten_dict_lists(d['euicc_configured_addresses']))
305
306 set_def_dp_addr_parser = argparse.ArgumentParser()
307 set_def_dp_addr_parser.add_argument('DP_ADDRESS', help='Default SM-DP+ address as UTF-8 string')
308
309 @cmd2.with_argparser(set_def_dp_addr_parser)
310 def do_set_default_dp_address(self, opts):
311 """Perform an ES10a SetDefaultDpAddress function."""
312 sdda_cmd = SetDefaultDpAddress(children=[DefaultDpAddress(decoded=opts.DP_ADDRESS)])
313 sdda = ADF_ISDR.store_data_tlv(self._cmd.lchan.scc, sdda_cmd, SetDefaultDpAddress)
314 d = sdda.to_dict()
315 self._cmd.poutput_json(flatten_dict_lists(d['set_default_dp_address']))
316
317 def do_get_euicc_challenge(self, opts):
318 """Perform an ES10b GetEUICCChallenge function."""
319 gec = ADF_ISDR.store_data_tlv(self._cmd.lchan.scc, GetEuiccChallenge(), GetEuiccChallenge)
320 d = gec.to_dict()
321 self._cmd.poutput_json(flatten_dict_lists(d['get_euicc_challenge']))
322
323 def do_get_euicc_info1(self, opts):
324 """Perform an ES10b GetEUICCInfo (1) function."""
325 ei1 = ADF_ISDR.store_data_tlv(self._cmd.lchan.scc, EuiccInfo1(), EuiccInfo1)
326 d = ei1.to_dict()
327 self._cmd.poutput_json(flatten_dict_lists(d['euicc_info1']))
328
329 def do_get_euicc_info2(self, opts):
330 """Perform an ES10b GetEUICCInfo (2) function."""
331 ei2 = ADF_ISDR.store_data_tlv(self._cmd.lchan.scc, EuiccInfo2(), EuiccInfo2)
332 d = ei2.to_dict()
333 self._cmd.poutput_json(flatten_dict_lists(d['euicc_info2']))
334
335 def do_list_notification(self, opts):
336 """Perform an ES10b ListNotification function."""
337 ln = ADF_ISDR.store_data_tlv(self._cmd.lchan.scc, ListNotificationReq(), ListNotificationResp)
338 d = ln.to_dict()
339 self._cmd.poutput_json(flatten_dict_lists(d['list_notification_resp']))
340
341 rem_notif_parser = argparse.ArgumentParser()
342 rem_notif_parser.add_argument('SEQ_NR', type=int, help='Sequence Number of the to-be-removed notification')
343
344 @cmd2.with_argparser(rem_notif_parser)
345 def do_remove_notification_from_list(self, opts):
346 """Perform an ES10b RemoveNotificationFromList function."""
347 rn_cmd = NotificationSentReq(children=[SeqNumber(decoded=opts.SEQ_NR)])
348 rn = ADF_ISDR.store_data_tlv(self._cmd.lchan.scc, rn_cmd, NotificationSentResp)
349 d = rn.to_dict()
350 self._cmd.poutput_json(flatten_dict_lists(d['notification_sent_resp']))
351
Harald Welte884eb552023-10-24 11:03:50 +0200352 def do_get_profiles_info(self, opts):
353 """Perform an ES10c GetProfilesInfo function."""
354 pi = ADF_ISDR.store_data_tlv(self._cmd.lchan.scc, ProfileInfoListReq(), ProfileInfoListResp)
355 d = pi.to_dict()
356 self._cmd.poutput_json(flatten_dict_lists(d['profile_info_list_resp']))
357
Harald Welte268a2022023-10-22 13:12:11 +0200358 en_prof_parser = argparse.ArgumentParser()
359 en_prof_grp = en_prof_parser.add_mutually_exclusive_group()
360 en_prof_grp.add_argument('--isdp-aid', help='Profile identified by its ISD-P AID')
361 en_prof_grp.add_argument('--iccid', help='Profile identified by its ICCID')
362 en_prof_parser.add_argument('--refresh-required', action='store_true', help='whether a REFRESH is required')
363
364 @cmd2.with_argparser(en_prof_parser)
365 def do_enable_profile(self, opts):
366 """Perform an ES10c EnableProfile function."""
367 ep_cmd_contents = []
368 if opts.isdp_aid:
369 ep_cmd_contents.append(IsdpAid(decoded=opts.isdp_aid))
370 if opts.iccid:
371 ep_cmd_contents.append(Iccid(decoded=opts.iccid))
372 if opts.refresh_required:
373 ep_cmd_contents.append(RefreshFlag())
374 ep_cmd = EnableProfileReq(children=ep_cmd_contents)
375 ep = ADF_ISDR.store_data_tlv(self._cmd.lchan.scc, ep_cmd, EnableProfileResp)
376 d = ep.to_dict()
377 self._cmd.poutput_json(flatten_dict_lists(d['enable_profile_resp']))
378
379 dis_prof_parser = argparse.ArgumentParser()
380 dis_prof_grp = dis_prof_parser.add_mutually_exclusive_group()
381 dis_prof_grp.add_argument('--isdp-aid', help='Profile identified by its ISD-P AID')
382 dis_prof_grp.add_argument('--iccid', help='Profile identified by its ICCID')
383 dis_prof_parser.add_argument('--refresh-required', action='store_true', help='whether a REFRESH is required')
384
385 @cmd2.with_argparser(dis_prof_parser)
386 def do_disable_profile(self, opts):
387 """Perform an ES10c DisableProfile function."""
388 dp_cmd_contents = []
389 if opts.isdp_aid:
390 dp_cmd_contents.append(IsdpAid(decoded=opts.isdp_aid))
391 if opts.iccid:
392 dp_cmd_contents.append(Iccid(decoded=opts.iccid))
393 if opts.refresh_required:
394 dp_cmd_contents.append(RefreshFlag())
395 dp_cmd = DisableProfileReq(children=dp_cmd_contents)
396 dp = ADF_ISDR.store_data_tlv(self._cmd.lchan.scc, dp_cmd, DisableProfileResp)
397 d = dp.to_dict()
398 self._cmd.poutput_json(flatten_dict_lists(d['disable_profile_resp']))
399
400 del_prof_parser = argparse.ArgumentParser()
401 del_prof_grp = del_prof_parser.add_mutually_exclusive_group()
402 del_prof_grp.add_argument('--isdp-aid', help='Profile identified by its ISD-P AID')
403 del_prof_grp.add_argument('--iccid', help='Profile identified by its ICCID')
404
405 @cmd2.with_argparser(del_prof_parser)
406 def do_delete_profile(self, opts):
407 """Perform an ES10c DeleteProfile function."""
408 dp_cmd_contents = []
409 if opts.isdp_aid:
410 dp_cmd_contents.append(IsdpAid(decoded=opts.isdp_aid))
411 if opts.iccid:
412 dp_cmd_contents.append(Iccid(decoded=opts.iccid))
413 dp_cmd = DeleteProfileReq(children=dp_cmd_contents)
414 dp = ADF_ISDR.store_data_tlv(self._cmd.lchan.scc, dp_cmd, DeleteProfileResp)
415 d = dp.to_dict()
416 self._cmd.poutput_json(flatten_dict_lists(d['delete_profile_resp']))
417
418
419 def do_get_eid(self, opts):
420 """Perform an ES10c GetEID function."""
421 (data, sw) = ADF_ISDR.store_data(self._cmd.lchan.scc, 'BF3E035C015A')
422 ged_cmd = GetEuiccData(children=[TagList(decoded=[0x5A])])
423 ged = ADF_ISDR.store_data_tlv(self._cmd.lchan.scc, ged_cmd, GetEuiccData)
424 d = ged.to_dict()
425 self._cmd.poutput_json(flatten_dict_lists(d['get_euicc_data']))
426
427 set_nickname_parser = argparse.ArgumentParser()
428 set_nickname_parser.add_argument('ICCID', help='ICCID of the profile whose nickname to set')
429 set_nickname_parser.add_argument('--profile-nickname', help='Nickname of the profile')
430
431 @cmd2.with_argparser(set_nickname_parser)
432 def do_set_nickname(self, opts):
433 """Perform an ES10c SetNickname function."""
434 nickname = opts.profile_nickname or ''
435 sn_cmd_contents = [Iccid(decoded=opts.ICCID), ProfileNickname(decoded=nickname)]
436 sn_cmd = SetNicknameReq(children=sn_cmd_contents)
437 sn = ADF_ISDR.store_data_tlv(self._cmd.lchan.scc, sn_cmd, SetNicknameResp)
438 d = sn.to_dict()
439 self._cmd.poutput_json(flatten_dict_lists(d['set_nickname_resp']))
440
441class ADF_ECASD(CardADF):
442 def __init__(self, aid=AID_ECASD, name='ADF.ECASD', fid=None, sfid=None,
443 desc='ECASD (eUICC Controlling Authority Security Domain) Application'):
444 super().__init__(aid=aid, fid=fid, sfid=sfid, name=name, desc=desc)
445 self.shell_commands += [self.AddlShellCommands()]
446
447 def decode_select_response(self, data_hex: Hexstr) -> object:
448 t = FciTemplate()
449 t.from_tlv(h2b(data_hex))
450 d = t.to_dict()
451 return flatten_dict_lists(d['fci_template'])
452
453 @with_default_category('Application-Specific Commands')
454 class AddlShellCommands(CommandSet):
455 pass
456
457
458
459class CardApplicationISDR(CardApplication):
460 def __init__(self):
461 super().__init__('ISD-R', adf=ADF_ISDR(), sw=sw_isdr)
462
463class CardApplicationECASD(CardApplication):
464 def __init__(self):
465 super().__init__('ECASD', adf=ADF_ECASD(), sw=sw_isdr)