Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 1 | # -*- coding: utf-8 -*- |
| 2 | |
| 3 | # without this, pylint will fail when inner classes are used |
| 4 | # within the 'nested' kwarg of our TlvMeta metaclass on python 3.7 :( |
| 5 | # pylint: disable=undefined-variable |
| 6 | |
| 7 | """ |
| 8 | Support for the Secure Element Access Control, specifically the ARA-M inside an UICC. |
| 9 | """ |
| 10 | |
| 11 | # |
| 12 | # Copyright (C) 2021 Harald Welte <laforge@osmocom.org> |
| 13 | # |
| 14 | # This program is free software: you can redistribute it and/or modify |
| 15 | # it under the terms of the GNU General Public License as published by |
| 16 | # the Free Software Foundation, either version 2 of the License, or |
| 17 | # (at your option) any later version. |
| 18 | # |
| 19 | # This program is distributed in the hope that it will be useful, |
| 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 22 | # GNU General Public License for more details. |
| 23 | # |
| 24 | # You should have received a copy of the GNU General Public License |
| 25 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 26 | # |
| 27 | |
| 28 | |
| 29 | from construct import * |
| 30 | from construct import Optional as COptional |
| 31 | from pySim.construct import * |
| 32 | from pySim.filesystem import * |
| 33 | from pySim.tlv import * |
| 34 | |
| 35 | # various BER-TLV encoded Data Objects (DOs) |
| 36 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 37 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 38 | class AidRefDO(BER_TLV_IE, tag=0x4f): |
| 39 | # SEID v1.1 Table 6-3 |
| 40 | _construct = HexAdapter(GreedyBytes) |
| 41 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 42 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 43 | class AidRefEmptyDO(BER_TLV_IE, tag=0xc0): |
| 44 | # SEID v1.1 Table 6-3 |
| 45 | pass |
| 46 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 47 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 48 | class DevAppIdRefDO(BER_TLV_IE, tag=0xc1): |
| 49 | # SEID v1.1 Table 6-4 |
| 50 | _construct = HexAdapter(GreedyBytes) |
| 51 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 52 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 53 | class PkgRefDO(BER_TLV_IE, tag=0xca): |
| 54 | # Android UICC Carrier Privileges specific extension, see https://source.android.com/devices/tech/config/uicc |
| 55 | _construct = Struct('package_name_string'/GreedyString("ascii")) |
| 56 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 57 | |
| 58 | class RefDO(BER_TLV_IE, tag=0xe1, nested=[AidRefDO, AidRefEmptyDO, DevAppIdRefDO, PkgRefDO]): |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 59 | # SEID v1.1 Table 6-5 |
| 60 | pass |
| 61 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 62 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 63 | class ApduArDO(BER_TLV_IE, tag=0xd0): |
| 64 | # SEID v1.1 Table 6-8 |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 65 | def _from_bytes(self, do: bytes): |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 66 | if len(do) == 1: |
| 67 | if do[0] == 0x00: |
| 68 | self.decoded = {'generic_access_rule': 'never'} |
| 69 | return self.decoded |
| 70 | elif do[0] == 0x01: |
| 71 | self.decoded = {'generic_access_rule': 'always'} |
| 72 | return self.decoded |
| 73 | else: |
| 74 | return ValueError('Invalid 1-byte generic APDU access rule') |
| 75 | else: |
| 76 | if len(do) % 8: |
| 77 | return ValueError('Invalid non-modulo-8 length of APDU filter: %d' % len(do)) |
| 78 | self.decoded['apdu_filter'] = [] |
| 79 | offset = 0 |
| 80 | while offset < len(do): |
| 81 | self.decoded['apdu_filter'] += {'header': b2h(do[offset:offset+4]), |
| 82 | 'mask': b2h(do[offset+4:offset+8])} |
| 83 | self.decoded = res |
| 84 | return res |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 85 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 86 | def _to_bytes(self): |
| 87 | if 'generic_access_rule' in self.decoded: |
| 88 | if self.decoded['generic_access_rule'] == 'never': |
| 89 | return b'\x00' |
| 90 | elif self.decoded['generic_access_rule'] == 'always': |
| 91 | return b'\x01' |
| 92 | else: |
| 93 | return ValueError('Invalid 1-byte generic APDU access rule') |
| 94 | else: |
| 95 | if not 'apdu_filter' in self.decoded: |
| 96 | return ValueError('Invalid APDU AR DO') |
| 97 | filters = self.decoded['apdu_filter'] |
| 98 | res = b'' |
| 99 | for f in filters: |
| 100 | if not 'header' in f or not 'mask' in f: |
| 101 | return ValueError('APDU filter must contain header and mask') |
| 102 | header_b = h2b(f['header']) |
| 103 | mask_b = h2b(f['mask']) |
| 104 | if len(header_b) != 4 or len(mask_b) != 4: |
| 105 | return ValueError('APDU filter header and mask must each be 4 bytes') |
| 106 | res += header_b + mask_b |
| 107 | return res |
| 108 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 109 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 110 | class NfcArDO(BER_TLV_IE, tag=0xd1): |
| 111 | # SEID v1.1 Table 6-9 |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 112 | _construct = Struct('nfc_event_access_rule' / |
| 113 | Enum(Int8ub, never=0, always=1)) |
| 114 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 115 | |
| 116 | class PermArDO(BER_TLV_IE, tag=0xdb): |
| 117 | # Android UICC Carrier Privileges specific extension, see https://source.android.com/devices/tech/config/uicc |
| 118 | _construct = Struct('permissions'/HexAdapter(Bytes(8))) |
| 119 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 120 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 121 | class ArDO(BER_TLV_IE, tag=0xe3, nested=[ApduArDO, NfcArDO, PermArDO]): |
| 122 | # SEID v1.1 Table 6-7 |
| 123 | pass |
| 124 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 125 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 126 | class RefArDO(BER_TLV_IE, tag=0xe2, nested=[RefDO, ArDO]): |
| 127 | # SEID v1.1 Table 6-6 |
| 128 | pass |
| 129 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 130 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 131 | class ResponseAllRefArDO(BER_TLV_IE, tag=0xff40, nested=[RefArDO]): |
| 132 | # SEID v1.1 Table 4-2 |
| 133 | pass |
| 134 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 135 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 136 | class ResponseArDO(BER_TLV_IE, tag=0xff50, nested=[ArDO]): |
| 137 | # SEID v1.1 Table 4-3 |
| 138 | pass |
| 139 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 140 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 141 | class ResponseRefreshTagDO(BER_TLV_IE, tag=0xdf20): |
| 142 | # SEID v1.1 Table 4-4 |
| 143 | _construct = Struct('refresh_tag'/HexAdapter(Bytes(8))) |
| 144 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 145 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 146 | class DeviceInterfaceVersionDO(BER_TLV_IE, tag=0xe6): |
| 147 | # SEID v1.1 Table 6-12 |
| 148 | _construct = Struct('major'/Int8ub, 'minor'/Int8ub, 'patch'/Int8ub) |
| 149 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 150 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 151 | class DeviceConfigDO(BER_TLV_IE, tag=0xe4, nested=[DeviceInterfaceVersionDO]): |
| 152 | # SEID v1.1 Table 6-10 |
| 153 | pass |
| 154 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 155 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 156 | class ResponseDeviceConfigDO(BER_TLV_IE, tag=0xff7f, nested=[DeviceConfigDO]): |
| 157 | # SEID v1.1 Table 5-14 |
| 158 | pass |
| 159 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 160 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 161 | class AramConfigDO(BER_TLV_IE, tag=0xe5, nested=[DeviceInterfaceVersionDO]): |
| 162 | # SEID v1.1 Table 6-11 |
| 163 | pass |
| 164 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 165 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 166 | class ResponseAramConfigDO(BER_TLV_IE, tag=0xdf21, nested=[AramConfigDO]): |
| 167 | # SEID v1.1 Table 4-5 |
| 168 | pass |
| 169 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 170 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 171 | class CommandStoreRefArDO(BER_TLV_IE, tag=0xf0, nested=[RefArDO]): |
| 172 | # SEID v1.1 Table 5-2 |
| 173 | pass |
| 174 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 175 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 176 | class CommandDelete(BER_TLV_IE, tag=0xf1, nested=[AidRefDO, AidRefEmptyDO, RefDO, RefArDO]): |
| 177 | # SEID v1.1 Table 5-4 |
| 178 | pass |
| 179 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 180 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 181 | class CommandUpdateRefreshTagDO(BER_TLV_IE, tag=0xf2): |
| 182 | # SEID V1.1 Table 5-6 |
| 183 | pass |
| 184 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 185 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 186 | class CommandRegisterClientAidsDO(BER_TLV_IE, tag=0xf7, nested=[AidRefDO, AidRefEmptyDO]): |
| 187 | # SEID v1.1 Table 5-7 |
| 188 | pass |
| 189 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 190 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 191 | class CommandGet(BER_TLV_IE, tag=0xf3, nested=[AidRefDO, AidRefEmptyDO]): |
| 192 | # SEID v1.1 Table 5-8 |
| 193 | pass |
| 194 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 195 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 196 | class CommandGetAll(BER_TLV_IE, tag=0xf4): |
| 197 | # SEID v1.1 Table 5-9 |
| 198 | pass |
| 199 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 200 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 201 | class CommandGetClientAidsDO(BER_TLV_IE, tag=0xf6): |
| 202 | # SEID v1.1 Table 5-10 |
| 203 | pass |
| 204 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 205 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 206 | class CommandGetNext(BER_TLV_IE, tag=0xf5): |
| 207 | # SEID v1.1 Table 5-11 |
| 208 | pass |
| 209 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 210 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 211 | class CommandGetDeviceConfigDO(BER_TLV_IE, tag=0xf8): |
| 212 | # SEID v1.1 Table 5-12 |
| 213 | pass |
| 214 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 215 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 216 | class ResponseAracAidDO(BER_TLV_IE, tag=0xff70, nested=[AidRefDO, AidRefEmptyDO]): |
| 217 | # SEID v1.1 Table 5-13 |
| 218 | pass |
| 219 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 220 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 221 | class BlockDO(BER_TLV_IE, tag=0xe7): |
| 222 | # SEID v1.1 Table 6-13 |
| 223 | _construct = Struct('offset'/Int16ub, 'length'/Int8ub) |
| 224 | |
| 225 | |
| 226 | # SEID v1.1 Table 4-1 |
| 227 | class GetCommandDoCollection(TLV_IE_Collection, nested=[RefDO, DeviceConfigDO]): |
| 228 | pass |
| 229 | |
| 230 | # SEID v1.1 Table 4-2 |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 231 | |
| 232 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 233 | class GetResponseDoCollection(TLV_IE_Collection, nested=[ResponseAllRefArDO, ResponseArDO, |
| 234 | ResponseRefreshTagDO, ResponseAramConfigDO]): |
| 235 | pass |
| 236 | |
| 237 | # SEID v1.1 Table 5-1 |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 238 | |
| 239 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 240 | class StoreCommandDoCollection(TLV_IE_Collection, |
| 241 | nested=[BlockDO, CommandStoreRefArDO, CommandDelete, |
| 242 | CommandUpdateRefreshTagDO, CommandRegisterClientAidsDO, |
| 243 | CommandGet, CommandGetAll, CommandGetClientAidsDO, |
| 244 | CommandGetNext, CommandGetDeviceConfigDO]): |
| 245 | pass |
| 246 | |
| 247 | |
| 248 | # SEID v1.1 Section 5.1.2 |
| 249 | class StoreResponseDoCollection(TLV_IE_Collection, |
| 250 | nested=[ResponseAllRefArDO, ResponseAracAidDO, ResponseDeviceConfigDO]): |
| 251 | pass |
| 252 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 253 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 254 | class ADF_ARAM(CardADF): |
| 255 | def __init__(self, aid='a00000015141434c00', name='ADF.ARA-M', fid=None, sfid=None, |
| 256 | desc='ARA-M Application'): |
| 257 | super().__init__(aid=aid, fid=fid, sfid=sfid, name=name, desc=desc) |
| 258 | self.shell_commands += [self.AddlShellCommands()] |
| 259 | files = [] |
| 260 | self.add_files(files) |
| 261 | |
| 262 | @staticmethod |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 263 | def xceive_apdu_tlv(tp, hdr: Hexstr, cmd_do, resp_cls, exp_sw='9000'): |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 264 | """Transceive an APDU with the card, transparently encoding the command data from TLV |
| 265 | and decoding the response data tlv.""" |
| 266 | if cmd_do: |
| 267 | cmd_do_enc = cmd_do.to_ie() |
| 268 | cmd_do_len = len(cmd_do_enc) |
| 269 | if cmd_do_len > 255: |
| 270 | return ValueError('DO > 255 bytes not supported yet') |
| 271 | else: |
| 272 | cmd_do_enc = b'' |
| 273 | cmd_do_len = 0 |
| 274 | c_apdu = hdr + ('%02x' % cmd_do_len) + b2h(cmd_do_enc) |
| 275 | (data, sw) = tp.send_apdu_checksw(c_apdu, exp_sw) |
| 276 | if data: |
| 277 | if resp_cls: |
| 278 | resp_do = resp_cls() |
| 279 | resp_do.from_tlv(h2b(data)) |
| 280 | return resp_do |
| 281 | else: |
| 282 | return data |
| 283 | else: |
| 284 | return None |
| 285 | |
| 286 | @staticmethod |
| 287 | def store_data(tp, do) -> bytes: |
| 288 | """Build the Command APDU for STORE DATA.""" |
| 289 | return ADF_ARAM.xceive_apdu_tlv(tp, '80e29000', do, StoreResponseDoCollection) |
| 290 | |
| 291 | @staticmethod |
| 292 | def get_all(tp): |
| 293 | return ADF_ARAM.xceive_apdu_tlv(tp, '80caff40', None, GetResponseDoCollection) |
| 294 | |
| 295 | @staticmethod |
| 296 | def get_config(tp, v_major=0, v_minor=0, v_patch=1): |
| 297 | cmd_do = DeviceConfigDO() |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 298 | cmd_do.from_dict([{'DeviceInterfaceVersionDO': { |
| 299 | 'major': v_major, 'minor': v_minor, 'patch': v_patch}}]) |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 300 | return ADF_ARAM.xceive_apdu_tlv(tp, '80cadf21', cmd_do, ResponseAramConfigDO) |
| 301 | |
| 302 | @with_default_category('Application-Specific Commands') |
| 303 | class AddlShellCommands(CommandSet): |
| 304 | def __init(self): |
| 305 | super().__init__() |
| 306 | |
| 307 | def do_aram_get_all(self, opts): |
| 308 | """GET DATA [All] on the ARA-M Applet""" |
| 309 | res_do = ADF_ARAM.get_all(self._cmd.card._scc._tp) |
| 310 | if res_do: |
| 311 | self._cmd.poutput_json(res_do.to_dict()) |
| 312 | |
| 313 | def do_aram_get_config(self, opts): |
Harald Welte | 12af793 | 2022-02-15 16:39:08 +0100 | [diff] [blame] | 314 | """Perform GET DATA [Config] on the ARA-M Applet: Tell it our version and retrieve its version.""" |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 315 | res_do = ADF_ARAM.get_config(self._cmd.card._scc._tp) |
| 316 | if res_do: |
| 317 | self._cmd.poutput_json(res_do.to_dict()) |
| 318 | |
| 319 | store_ref_ar_do_parse = argparse.ArgumentParser() |
| 320 | # REF-DO |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 321 | store_ref_ar_do_parse.add_argument( |
| 322 | '--device-app-id', required=True, help='Identifies the specific device application that the rule appplies to. Hash of Certificate of Application Provider, or UUID. (20/32 hex bytes)') |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 323 | aid_grp = store_ref_ar_do_parse.add_mutually_exclusive_group() |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 324 | aid_grp.add_argument( |
| 325 | '--aid', help='Identifies the specific SE application for which rules are to be stored. Can be a partial AID, containing for example only the RID. (5-16 hex bytes)') |
| 326 | aid_grp.add_argument('--aid-empty', action='store_true', |
| 327 | help='No specific SE application, applies to all applications') |
| 328 | store_ref_ar_do_parse.add_argument( |
| 329 | '--pkg-ref', help='Full Android Java package name (up to 127 chars ASCII)') |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 330 | # AR-DO |
| 331 | apdu_grp = store_ref_ar_do_parse.add_mutually_exclusive_group() |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 332 | apdu_grp.add_argument( |
| 333 | '--apdu-never', action='store_true', help='APDU access is not allowed') |
| 334 | apdu_grp.add_argument( |
| 335 | '--apdu-always', action='store_true', help='APDU access is allowed') |
| 336 | apdu_grp.add_argument( |
| 337 | '--apdu-filter', help='APDU filter: 4 byte CLA/INS/P1/P2 followed by 4 byte mask (8 hex bytes)') |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 338 | nfc_grp = store_ref_ar_do_parse.add_mutually_exclusive_group() |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 339 | nfc_grp.add_argument('--nfc-always', action='store_true', |
| 340 | help='NFC event access is allowed') |
| 341 | nfc_grp.add_argument('--nfc-never', action='store_true', |
| 342 | help='NFC event access is not allowed') |
| 343 | store_ref_ar_do_parse.add_argument( |
| 344 | '--android-permissions', help='Android UICC Carrier Privilege Permissions (8 hex bytes)') |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 345 | |
| 346 | @cmd2.with_argparser(store_ref_ar_do_parse) |
| 347 | def do_aram_store_ref_ar_do(self, opts): |
Harald Welte | 12af793 | 2022-02-15 16:39:08 +0100 | [diff] [blame] | 348 | """Perform STORE DATA [Command-Store-REF-AR-DO] to store a (new) access rule.""" |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 349 | # REF |
| 350 | ref_do_content = [] |
| 351 | if opts.aid: |
| 352 | ref_do_content += [{'AidRefDO': opts.aid}] |
| 353 | elif opts.aid_empty: |
| 354 | ref_do_content += [{'AidRefEmptyDO': None}] |
| 355 | ref_do_content += [{'DevAppIdRefDO': opts.device_app_id}] |
| 356 | if opts.pkg_ref: |
| 357 | ref_do_content += [{'PkgRefDO': opts.pkg_ref}] |
| 358 | # AR |
| 359 | ar_do_content = [] |
| 360 | if opts.apdu_never: |
| 361 | ar_do_content += [{'ApduArDO': {'generic_access_rule': 'never'}}] |
| 362 | elif opts.apdu_always: |
| 363 | ar_do_content += [{'ApduArDO': {'generic_access_rule': 'always'}}] |
| 364 | elif opts.apdu_filter: |
| 365 | # TODO: multiple filters |
| 366 | ar_do_content += [{'ApduArDO': {'apdu_filter': [opts.apdu_filter]}}] |
| 367 | if opts.nfc_always: |
| 368 | ar_do_content += [{'NfcArDO': {'nfc_event_access_rule': 'always'}}] |
| 369 | elif opts.nfc_never: |
| 370 | ar_do_content += [{'NfcArDO': {'nfc_event_access_rule': 'never'}}] |
| 371 | if opts.android_permissions: |
| 372 | ar_do_content += [{'PermArDO': {'permissions': opts.android_permissions}}] |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 373 | d = [{'RefArDO': [{'RefDO': ref_do_content}, {'ArDO': ar_do_content}]}] |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 374 | csrado = CommandStoreRefArDO() |
| 375 | csrado.from_dict(d) |
| 376 | res_do = ADF_ARAM.store_data(self._cmd.card._scc._tp, csrado) |
| 377 | if res_do: |
| 378 | self._cmd.poutput_json(res_do.to_dict()) |
| 379 | |
| 380 | def do_aram_delete_all(self, opts): |
| 381 | """Perform STORE DATA [Command-Delete[all]] to delete all access rules.""" |
| 382 | deldo = CommandDelete() |
| 383 | res_do = ADF_ARAM.store_data(self._cmd.card._scc._tp, deldo) |
| 384 | if res_do: |
| 385 | self._cmd.poutput_json(res_do.to_dict()) |
| 386 | |
| 387 | |
| 388 | # SEAC v1.1 Section 4.1.2.2 + 5.1.2.2 |
| 389 | sw_aram = { |
| 390 | 'ARA-M': { |
| 391 | '6381': 'Rule successfully stored but an access rule already exists', |
| 392 | '6382': 'Rule successfully stored bu contained at least one unknown (discarded) BER-TLV', |
| 393 | '6581': 'Memory Problem', |
| 394 | '6700': 'Wrong Length in Lc', |
| 395 | '6981': 'DO is not supported by the ARA-M/ARA-C', |
| 396 | '6982': 'Security status not satisfied', |
| 397 | '6984': 'Rules have been updated and must be read again / logical channels in use', |
| 398 | '6985': 'Conditions not satisfied', |
| 399 | '6a80': 'Incorrect values in the command data', |
| 400 | '6a84': 'Rules have been updated and must be read again', |
| 401 | '6a86': 'Incorrect P1 P2', |
| 402 | '6a88': 'Referenced data not found', |
| 403 | '6a89': 'Conflicting access rule already exists in the Secure Element', |
| 404 | '6d00': 'Invalid instruction', |
| 405 | '6e00': 'Invalid class', |
| 406 | } |
| 407 | } |
| 408 | |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 409 | |
Harald Welte | 95ce6b1 | 2021-10-20 18:40:54 +0200 | [diff] [blame] | 410 | class CardApplicationARAM(CardApplication): |
| 411 | def __init__(self): |
Harald Welte | c91085e | 2022-02-10 18:05:45 +0100 | [diff] [blame] | 412 | super().__init__('ARA-M', adf=ADF_ARAM(), sw=sw_aram) |