pymobiledevice3 4.14.6__py3-none-any.whl → 7.0.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- misc/plist_sniffer.py +15 -15
- misc/remotexpc_sniffer.py +29 -28
- misc/understanding_idevice_protocol_layers.md +15 -10
- pymobiledevice3/__main__.py +317 -127
- pymobiledevice3/_version.py +22 -4
- pymobiledevice3/bonjour.py +358 -113
- pymobiledevice3/ca.py +253 -16
- pymobiledevice3/cli/activation.py +31 -23
- pymobiledevice3/cli/afc.py +49 -40
- pymobiledevice3/cli/amfi.py +16 -21
- pymobiledevice3/cli/apps.py +87 -42
- pymobiledevice3/cli/backup.py +160 -90
- pymobiledevice3/cli/bonjour.py +44 -40
- pymobiledevice3/cli/cli_common.py +204 -198
- pymobiledevice3/cli/companion_proxy.py +14 -14
- pymobiledevice3/cli/crash.py +105 -56
- pymobiledevice3/cli/developer/__init__.py +62 -0
- pymobiledevice3/cli/developer/accessibility/__init__.py +65 -0
- pymobiledevice3/cli/developer/accessibility/settings.py +43 -0
- pymobiledevice3/cli/developer/arbitration.py +50 -0
- pymobiledevice3/cli/developer/condition.py +33 -0
- pymobiledevice3/cli/developer/core_device.py +294 -0
- pymobiledevice3/cli/developer/debugserver.py +244 -0
- pymobiledevice3/cli/developer/dvt/__init__.py +438 -0
- pymobiledevice3/cli/developer/dvt/core_profile_session.py +295 -0
- pymobiledevice3/cli/developer/dvt/simulate_location.py +56 -0
- pymobiledevice3/cli/developer/dvt/sysmon/__init__.py +69 -0
- pymobiledevice3/cli/developer/dvt/sysmon/process.py +188 -0
- pymobiledevice3/cli/developer/fetch_symbols.py +108 -0
- pymobiledevice3/cli/developer/simulate_location.py +51 -0
- pymobiledevice3/cli/diagnostics/__init__.py +75 -0
- pymobiledevice3/cli/diagnostics/battery.py +47 -0
- pymobiledevice3/cli/idam.py +42 -0
- pymobiledevice3/cli/lockdown.py +108 -103
- pymobiledevice3/cli/mounter.py +158 -99
- pymobiledevice3/cli/notification.py +38 -26
- pymobiledevice3/cli/pcap.py +45 -24
- pymobiledevice3/cli/power_assertion.py +18 -17
- pymobiledevice3/cli/processes.py +17 -23
- pymobiledevice3/cli/profile.py +165 -109
- pymobiledevice3/cli/provision.py +35 -34
- pymobiledevice3/cli/remote.py +217 -129
- pymobiledevice3/cli/restore.py +159 -143
- pymobiledevice3/cli/springboard.py +63 -53
- pymobiledevice3/cli/syslog.py +193 -86
- pymobiledevice3/cli/usbmux.py +73 -33
- pymobiledevice3/cli/version.py +5 -7
- pymobiledevice3/cli/webinspector.py +376 -214
- pymobiledevice3/common.py +3 -1
- pymobiledevice3/exceptions.py +182 -58
- pymobiledevice3/irecv.py +52 -53
- pymobiledevice3/irecv_devices.py +1489 -464
- pymobiledevice3/lockdown.py +473 -275
- pymobiledevice3/lockdown_service_provider.py +15 -8
- pymobiledevice3/osu/os_utils.py +27 -9
- pymobiledevice3/osu/posix_util.py +34 -15
- pymobiledevice3/osu/win_util.py +14 -8
- pymobiledevice3/pair_records.py +102 -21
- pymobiledevice3/remote/common.py +8 -4
- pymobiledevice3/remote/core_device/app_service.py +94 -67
- pymobiledevice3/remote/core_device/core_device_service.py +17 -14
- pymobiledevice3/remote/core_device/device_info.py +5 -5
- pymobiledevice3/remote/core_device/diagnostics_service.py +19 -4
- pymobiledevice3/remote/core_device/file_service.py +53 -23
- pymobiledevice3/remote/remote_service_discovery.py +79 -45
- pymobiledevice3/remote/remotexpc.py +73 -44
- pymobiledevice3/remote/tunnel_service.py +442 -317
- pymobiledevice3/remote/utils.py +14 -13
- pymobiledevice3/remote/xpc_message.py +145 -125
- pymobiledevice3/resources/dsc_uuid_map.py +19 -19
- pymobiledevice3/resources/firmware_notifications.py +20 -16
- pymobiledevice3/resources/notifications.txt +144 -0
- pymobiledevice3/restore/asr.py +27 -27
- pymobiledevice3/restore/base_restore.py +110 -21
- pymobiledevice3/restore/consts.py +87 -66
- pymobiledevice3/restore/device.py +59 -12
- pymobiledevice3/restore/fdr.py +46 -48
- pymobiledevice3/restore/ftab.py +19 -19
- pymobiledevice3/restore/img4.py +163 -0
- pymobiledevice3/restore/mbn.py +587 -0
- pymobiledevice3/restore/recovery.py +151 -151
- pymobiledevice3/restore/restore.py +562 -544
- pymobiledevice3/restore/restore_options.py +131 -110
- pymobiledevice3/restore/restored_client.py +51 -31
- pymobiledevice3/restore/tss.py +385 -267
- pymobiledevice3/service_connection.py +252 -59
- pymobiledevice3/services/accessibilityaudit.py +202 -120
- pymobiledevice3/services/afc.py +962 -365
- pymobiledevice3/services/amfi.py +24 -30
- pymobiledevice3/services/companion.py +23 -19
- pymobiledevice3/services/crash_reports.py +71 -47
- pymobiledevice3/services/debugserver_applist.py +3 -3
- pymobiledevice3/services/device_arbitration.py +8 -8
- pymobiledevice3/services/device_link.py +101 -79
- pymobiledevice3/services/diagnostics.py +973 -967
- pymobiledevice3/services/dtfetchsymbols.py +8 -8
- pymobiledevice3/services/dvt/dvt_secure_socket_proxy.py +4 -4
- pymobiledevice3/services/dvt/dvt_testmanaged_proxy.py +4 -4
- pymobiledevice3/services/dvt/instruments/activity_trace_tap.py +85 -74
- pymobiledevice3/services/dvt/instruments/application_listing.py +2 -3
- pymobiledevice3/services/dvt/instruments/condition_inducer.py +7 -6
- pymobiledevice3/services/dvt/instruments/core_profile_session_tap.py +466 -384
- pymobiledevice3/services/dvt/instruments/device_info.py +20 -11
- pymobiledevice3/services/dvt/instruments/energy_monitor.py +1 -1
- pymobiledevice3/services/dvt/instruments/graphics.py +1 -1
- pymobiledevice3/services/dvt/instruments/location_simulation.py +1 -1
- pymobiledevice3/services/dvt/instruments/location_simulation_base.py +10 -10
- pymobiledevice3/services/dvt/instruments/network_monitor.py +17 -17
- pymobiledevice3/services/dvt/instruments/notifications.py +1 -1
- pymobiledevice3/services/dvt/instruments/process_control.py +35 -10
- pymobiledevice3/services/dvt/instruments/screenshot.py +2 -2
- pymobiledevice3/services/dvt/instruments/sysmontap.py +15 -15
- pymobiledevice3/services/dvt/testmanaged/xcuitest.py +42 -52
- pymobiledevice3/services/file_relay.py +10 -10
- pymobiledevice3/services/heartbeat.py +9 -8
- pymobiledevice3/services/house_arrest.py +16 -15
- pymobiledevice3/services/idam.py +20 -0
- pymobiledevice3/services/installation_proxy.py +173 -81
- pymobiledevice3/services/lockdown_service.py +20 -10
- pymobiledevice3/services/misagent.py +22 -19
- pymobiledevice3/services/mobile_activation.py +147 -64
- pymobiledevice3/services/mobile_config.py +331 -294
- pymobiledevice3/services/mobile_image_mounter.py +141 -113
- pymobiledevice3/services/mobilebackup2.py +203 -145
- pymobiledevice3/services/notification_proxy.py +11 -11
- pymobiledevice3/services/os_trace.py +134 -74
- pymobiledevice3/services/pcapd.py +314 -302
- pymobiledevice3/services/power_assertion.py +10 -9
- pymobiledevice3/services/preboard.py +4 -4
- pymobiledevice3/services/remote_fetch_symbols.py +21 -14
- pymobiledevice3/services/remote_server.py +176 -146
- pymobiledevice3/services/restore_service.py +16 -16
- pymobiledevice3/services/screenshot.py +15 -12
- pymobiledevice3/services/simulate_location.py +7 -7
- pymobiledevice3/services/springboard.py +15 -15
- pymobiledevice3/services/syslog.py +5 -5
- pymobiledevice3/services/web_protocol/alert.py +11 -11
- pymobiledevice3/services/web_protocol/automation_session.py +251 -239
- pymobiledevice3/services/web_protocol/cdp_screencast.py +46 -37
- pymobiledevice3/services/web_protocol/cdp_server.py +19 -19
- pymobiledevice3/services/web_protocol/cdp_target.py +411 -373
- pymobiledevice3/services/web_protocol/driver.py +114 -111
- pymobiledevice3/services/web_protocol/element.py +124 -111
- pymobiledevice3/services/web_protocol/inspector_session.py +106 -102
- pymobiledevice3/services/web_protocol/selenium_api.py +49 -49
- pymobiledevice3/services/web_protocol/session_protocol.py +18 -12
- pymobiledevice3/services/web_protocol/switch_to.py +30 -27
- pymobiledevice3/services/webinspector.py +189 -155
- pymobiledevice3/tcp_forwarder.py +87 -69
- pymobiledevice3/tunneld/__init__.py +0 -0
- pymobiledevice3/tunneld/api.py +63 -0
- pymobiledevice3/tunneld/server.py +603 -0
- pymobiledevice3/usbmux.py +198 -147
- pymobiledevice3/utils.py +14 -11
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/METADATA +55 -28
- pymobiledevice3-7.0.6.dist-info/RECORD +188 -0
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/WHEEL +1 -1
- pymobiledevice3/cli/developer.py +0 -1215
- pymobiledevice3/cli/diagnostics.py +0 -99
- pymobiledevice3/tunneld.py +0 -524
- pymobiledevice3-4.14.6.dist-info/RECORD +0 -168
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info/licenses}/LICENSE +0 -0
- {pymobiledevice3-4.14.6.dist-info → pymobiledevice3-7.0.6.dist-info}/top_level.txt +0 -0
pymobiledevice3/restore/tss.py
CHANGED
|
@@ -7,112 +7,113 @@ from uuid import uuid4
|
|
|
7
7
|
|
|
8
8
|
import asn1
|
|
9
9
|
import requests
|
|
10
|
-
from ipsw_parser.img4 import COMPONENT_FOURCC
|
|
11
10
|
|
|
12
|
-
from pymobiledevice3.exceptions import PyMobileDevice3Exception
|
|
11
|
+
from pymobiledevice3.exceptions import PyMobileDevice3Exception, TSSError
|
|
12
|
+
from pymobiledevice3.restore.img4 import COMPONENT_FOURCC
|
|
13
13
|
from pymobiledevice3.utils import bytes_to_uint, plist_access_path
|
|
14
14
|
|
|
15
|
-
TSS_CONTROLLER_ACTION_URL =
|
|
15
|
+
TSS_CONTROLLER_ACTION_URL = "http://gs.apple.com/TSS/controller?action=2"
|
|
16
16
|
|
|
17
|
-
TSS_CLIENT_VERSION_STRING =
|
|
17
|
+
TSS_CLIENT_VERSION_STRING = "libauthinstall-1104.0.9"
|
|
18
18
|
|
|
19
19
|
logger = logging.getLogger(__name__)
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def get_with_or_without_comma(obj: dict, k: str, default=None):
|
|
23
|
-
val = obj.get(k, obj.get(k.replace(
|
|
23
|
+
val = obj.get(k, obj.get(k.replace(",", "")))
|
|
24
24
|
if val is None and default is not None:
|
|
25
25
|
val = default
|
|
26
26
|
return val
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
def is_fw_payload(info: dict[str, typing.Any]) -> bool:
|
|
30
|
-
return (
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
return (
|
|
31
|
+
info.get("IsFirmwarePayload")
|
|
32
|
+
or info.get("IsSecondaryFirmwarePayload")
|
|
33
|
+
or info.get("IsFUDFirmware")
|
|
34
|
+
or info.get("IsLoadedByiBoot")
|
|
35
|
+
or info.get("IsEarlyAccessFirmware")
|
|
36
|
+
or info.get("IsiBootEANFirmware")
|
|
37
|
+
or info.get("IsiBootNonEssentialFirmware")
|
|
38
|
+
)
|
|
33
39
|
|
|
34
40
|
|
|
35
41
|
class TSSResponse(dict):
|
|
36
42
|
@property
|
|
37
43
|
def ap_img4_ticket(self):
|
|
38
|
-
ticket = self.get(
|
|
44
|
+
ticket = self.get("ApImg4Ticket")
|
|
39
45
|
|
|
40
46
|
if ticket is None:
|
|
41
|
-
raise PyMobileDevice3Exception(
|
|
47
|
+
raise PyMobileDevice3Exception("TSS response doesn't contain a ApImg4Ticket")
|
|
42
48
|
|
|
43
49
|
return ticket
|
|
44
50
|
|
|
45
51
|
@property
|
|
46
52
|
def bb_ticket(self):
|
|
47
|
-
return self.get(
|
|
53
|
+
return self.get("BBTicket")
|
|
48
54
|
|
|
49
55
|
def get_path_by_entry(self, component: str):
|
|
50
56
|
node = self.get(component)
|
|
51
57
|
if node is not None:
|
|
52
|
-
return node.get(
|
|
58
|
+
return node.get("Path")
|
|
53
59
|
|
|
54
60
|
return None
|
|
55
61
|
|
|
56
62
|
|
|
57
63
|
class TSSRequest:
|
|
58
64
|
def __init__(self):
|
|
59
|
-
self._request = {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
self._request: dict[str, typing.Any] = {
|
|
66
|
+
"@HostPlatformInfo": "mac",
|
|
67
|
+
"@VersionInfo": TSS_CLIENT_VERSION_STRING,
|
|
68
|
+
"@UUID": str(uuid4()).upper(),
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
@staticmethod
|
|
66
72
|
def apply_restore_request_rules(tss_entry: dict, parameters: dict, rules: list) -> dict:
|
|
67
73
|
for rule in rules:
|
|
68
74
|
conditions_fulfilled = True
|
|
69
|
-
conditions = rule[
|
|
75
|
+
conditions = rule["Conditions"]
|
|
70
76
|
for key, value in conditions.items():
|
|
71
77
|
if not conditions_fulfilled:
|
|
72
78
|
break
|
|
73
79
|
|
|
74
|
-
if key ==
|
|
75
|
-
value2 = parameters.get(
|
|
76
|
-
elif key ==
|
|
77
|
-
value2 = parameters.get(
|
|
78
|
-
elif key ==
|
|
79
|
-
value2 = parameters.get(
|
|
80
|
-
elif key ==
|
|
81
|
-
value2 = parameters.get(
|
|
82
|
-
elif key ==
|
|
83
|
-
value2 = parameters.get(
|
|
84
|
-
elif key == 'ApInRomDFU':
|
|
85
|
-
value2 = parameters.get('ApInRomDFU')
|
|
80
|
+
if key == "ApRawProductionMode" or key == "ApCurrentProductionMode":
|
|
81
|
+
value2 = parameters.get("ApProductionMode")
|
|
82
|
+
elif key == "ApRawSecurityMode":
|
|
83
|
+
value2 = parameters.get("ApSecurityMode")
|
|
84
|
+
elif key == "ApRequiresImage4":
|
|
85
|
+
value2 = parameters.get("ApSupportsImg4")
|
|
86
|
+
elif key == "ApDemotionPolicyOverride":
|
|
87
|
+
value2 = parameters.get("DemotionPolicy")
|
|
88
|
+
elif key == "ApInRomDFU":
|
|
89
|
+
value2 = parameters.get("ApInRomDFU")
|
|
86
90
|
else:
|
|
87
|
-
logger.error(f
|
|
91
|
+
logger.error(f"Unhandled condition {key} while parsing RestoreRequestRules")
|
|
88
92
|
value2 = None
|
|
89
93
|
|
|
90
|
-
if value2
|
|
91
|
-
conditions_fulfilled = value == value2
|
|
92
|
-
else:
|
|
93
|
-
conditions_fulfilled = False
|
|
94
|
+
conditions_fulfilled = value == value2 if value2 else False
|
|
94
95
|
|
|
95
96
|
if not conditions_fulfilled:
|
|
96
97
|
continue
|
|
97
98
|
|
|
98
|
-
actions = rule[
|
|
99
|
+
actions = rule["Actions"]
|
|
99
100
|
for key, value in actions.items():
|
|
100
101
|
if value != 255:
|
|
101
102
|
value2 = tss_entry.get(key)
|
|
102
103
|
if value2:
|
|
103
104
|
tss_entry.pop(key)
|
|
104
|
-
logger.debug(f
|
|
105
|
+
logger.debug(f"Adding {key}={value} to TSS entry")
|
|
105
106
|
tss_entry[key] = value
|
|
106
107
|
return tss_entry
|
|
107
108
|
|
|
108
109
|
def add_tags(self, parameters: dict):
|
|
109
110
|
for key, value in parameters.items():
|
|
110
|
-
if isinstance(value, str) and value.startswith(
|
|
111
|
+
if isinstance(value, str) and value.startswith("0x"):
|
|
111
112
|
value = int(value, 16)
|
|
112
113
|
self._request[key] = value
|
|
113
114
|
|
|
114
115
|
def add_common_tags(self, parameters: dict, overrides=None):
|
|
115
|
-
keys = (
|
|
116
|
+
keys = ("ApECID", "UniqueBuildID", "ApChipID", "ApBoardID", "ApSecurityDomain")
|
|
116
117
|
for k in keys:
|
|
117
118
|
if k in parameters:
|
|
118
119
|
self._request[k] = parameters[k]
|
|
@@ -120,47 +121,73 @@ class TSSRequest:
|
|
|
120
121
|
self._request.update(overrides)
|
|
121
122
|
|
|
122
123
|
def add_ap_recovery_tags(self, parameters: dict, overrides=None):
|
|
123
|
-
skip_keys = (
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
skip_keys = (
|
|
125
|
+
"BasebandFirmware",
|
|
126
|
+
"SE,UpdatePayload",
|
|
127
|
+
"BaseSystem",
|
|
128
|
+
"ANS",
|
|
129
|
+
"Ap,AudioBootChime",
|
|
130
|
+
"Ap,CIO",
|
|
131
|
+
"Ap,RestoreCIO",
|
|
132
|
+
"Ap,RestoreTMU",
|
|
133
|
+
"Ap,TMU",
|
|
134
|
+
"Ap,rOSLogo1",
|
|
135
|
+
"Ap,rOSLogo2",
|
|
136
|
+
"AppleLogo",
|
|
137
|
+
"DCP",
|
|
138
|
+
"LLB",
|
|
139
|
+
"RecoveryMode",
|
|
140
|
+
"RestoreANS",
|
|
141
|
+
"RestoreDCP",
|
|
142
|
+
"RestoreDeviceTree",
|
|
143
|
+
"RestoreKernelCache",
|
|
144
|
+
"RestoreLogo",
|
|
145
|
+
"RestoreRamDisk",
|
|
146
|
+
"RestoreSEP",
|
|
147
|
+
"SEP",
|
|
148
|
+
"ftap",
|
|
149
|
+
"ftsp",
|
|
150
|
+
"iBEC",
|
|
151
|
+
"iBSS",
|
|
152
|
+
"rfta",
|
|
153
|
+
"rfts",
|
|
154
|
+
"Diags",
|
|
155
|
+
)
|
|
128
156
|
|
|
129
157
|
# add components to request
|
|
130
|
-
manifest = parameters[
|
|
158
|
+
manifest = parameters["Manifest"]
|
|
131
159
|
for key, manifest_entry in manifest.items():
|
|
132
160
|
if key in skip_keys:
|
|
133
161
|
continue
|
|
134
|
-
info = manifest_entry.get(
|
|
162
|
+
info = manifest_entry.get("Info")
|
|
135
163
|
if not info:
|
|
136
164
|
continue
|
|
137
|
-
if parameters.get(
|
|
138
|
-
if not manifest_entry.get(
|
|
139
|
-
logger.debug(f
|
|
165
|
+
if parameters.get("_OnlyFWComponents", False):
|
|
166
|
+
if not manifest_entry.get("Trusted", False):
|
|
167
|
+
logger.debug(f"skipping {key} as it is not trusted")
|
|
140
168
|
continue
|
|
141
|
-
info = manifest_entry[
|
|
169
|
+
info = manifest_entry["Info"]
|
|
142
170
|
if not is_fw_payload(info):
|
|
143
|
-
logger.debug(f
|
|
171
|
+
logger.debug(f"skipping {key} as it is not a firmware payload")
|
|
144
172
|
continue
|
|
145
173
|
|
|
146
174
|
# copy this entry
|
|
147
175
|
tss_entry = dict(manifest_entry)
|
|
148
176
|
|
|
149
177
|
# remove obsolete Info node
|
|
150
|
-
tss_entry.pop(
|
|
178
|
+
tss_entry.pop("Info")
|
|
151
179
|
|
|
152
180
|
# handle RestoreRequestRules
|
|
153
|
-
if
|
|
154
|
-
rules = manifest_entry[
|
|
181
|
+
if "Info" in manifest_entry and "RestoreRequestRules" in manifest_entry["Info"]:
|
|
182
|
+
rules = manifest_entry["Info"]["RestoreRequestRules"]
|
|
155
183
|
if rules:
|
|
156
|
-
logger.debug(f
|
|
184
|
+
logger.debug(f"Applying restore request rules for entry {key}")
|
|
157
185
|
tss_entry = self.apply_restore_request_rules(tss_entry, parameters, rules)
|
|
158
186
|
|
|
159
187
|
# Make sure we have a Digest key for Trusted items even if empty
|
|
160
|
-
node = manifest_entry.get(
|
|
161
|
-
if node:
|
|
162
|
-
|
|
163
|
-
tss_entry['Digest'] = b''
|
|
188
|
+
node = manifest_entry.get("Trusted", False)
|
|
189
|
+
if node and manifest_entry.get("Digest") is None:
|
|
190
|
+
tss_entry["Digest"] = b""
|
|
164
191
|
|
|
165
192
|
self._request[key] = tss_entry
|
|
166
193
|
|
|
@@ -168,18 +195,22 @@ class TSSRequest:
|
|
|
168
195
|
self._request.update(overrides)
|
|
169
196
|
|
|
170
197
|
def add_timer_tags(self, parameters: dict, overrides=None):
|
|
171
|
-
manifest = parameters[
|
|
198
|
+
manifest = parameters["Manifest"]
|
|
172
199
|
|
|
173
200
|
# add tags indicating we want to get the Timer ticket
|
|
174
|
-
self._request[
|
|
201
|
+
self._request["@BBTicket"] = True
|
|
175
202
|
|
|
176
|
-
key = f
|
|
203
|
+
key = f"@{parameters['TicketName']}"
|
|
177
204
|
self._request[key] = True
|
|
178
205
|
|
|
179
|
-
tag = parameters[
|
|
206
|
+
tag = parameters["TagNumber"]
|
|
180
207
|
|
|
181
|
-
keys_to_copy_uint = (
|
|
182
|
-
|
|
208
|
+
keys_to_copy_uint = (
|
|
209
|
+
f"Timer,BoardID,{tag}",
|
|
210
|
+
f"Timer,ChipID,{tag}",
|
|
211
|
+
f"Timer,SecurityDomain,{tag}",
|
|
212
|
+
f"Timer,ECID,{tag}",
|
|
213
|
+
)
|
|
183
214
|
|
|
184
215
|
for key in keys_to_copy_uint:
|
|
185
216
|
value = parameters.get(key)
|
|
@@ -189,38 +220,41 @@ class TSSRequest:
|
|
|
189
220
|
else:
|
|
190
221
|
self._request[key] = value
|
|
191
222
|
|
|
192
|
-
keys_to_copy_bool = (
|
|
223
|
+
keys_to_copy_bool = (
|
|
224
|
+
f"Timer,ProductionMode,{tag}",
|
|
225
|
+
f"Timer,SecurityMode,{tag}",
|
|
226
|
+
)
|
|
193
227
|
|
|
194
228
|
for key in keys_to_copy_bool:
|
|
195
229
|
value = parameters.get(key)
|
|
196
230
|
self._request[key] = bytes_to_uint(value) == 1
|
|
197
231
|
|
|
198
|
-
nonce = parameters.get(parameters, f
|
|
232
|
+
nonce = parameters.get(parameters, f"Timer,Nonce,{tag}")
|
|
199
233
|
|
|
200
234
|
if nonce is not None:
|
|
201
|
-
self._request[f
|
|
235
|
+
self._request[f"Timer,Nonce,{tag}"] = nonce
|
|
202
236
|
|
|
203
237
|
for comp_name, node in manifest.items():
|
|
204
|
-
if not comp_name.startswith(
|
|
238
|
+
if not comp_name.startswith("Timer,"):
|
|
205
239
|
continue
|
|
206
240
|
|
|
207
241
|
manifest_entry = dict(node)
|
|
208
242
|
|
|
209
243
|
# handle RestoreRequestRules
|
|
210
|
-
rules = manifest_entry[
|
|
244
|
+
rules = manifest_entry["Info"].get("RestoreRequestRules")
|
|
211
245
|
if rules is not None:
|
|
212
246
|
self.apply_restore_request_rules(manifest_entry, parameters, rules)
|
|
213
247
|
|
|
214
248
|
# Make sure we have a Digest key for Trusted items even if empty
|
|
215
|
-
trusted = manifest_entry.get(
|
|
249
|
+
trusted = manifest_entry.get("Trusted", False)
|
|
216
250
|
|
|
217
251
|
if trusted:
|
|
218
|
-
digest = manifest_entry.get(
|
|
252
|
+
digest = manifest_entry.get("Digest")
|
|
219
253
|
if digest is None:
|
|
220
|
-
logger.debug(f
|
|
221
|
-
manifest_entry[
|
|
254
|
+
logger.debug(f"No Digest data, using empty value for entry {comp_name}")
|
|
255
|
+
manifest_entry["Digest"] = b""
|
|
222
256
|
|
|
223
|
-
manifest_entry.pop(
|
|
257
|
+
manifest_entry.pop("Info")
|
|
224
258
|
|
|
225
259
|
# finally add entry to request
|
|
226
260
|
self._request[comp_name] = manifest_entry
|
|
@@ -229,110 +263,122 @@ class TSSRequest:
|
|
|
229
263
|
self._request.update(overrides)
|
|
230
264
|
|
|
231
265
|
def add_local_policy_tags(self, parameters: dict):
|
|
232
|
-
self._request[
|
|
266
|
+
self._request["@ApImg4Ticket"] = True
|
|
233
267
|
|
|
234
268
|
keys_to_copy = (
|
|
235
|
-
|
|
236
|
-
|
|
269
|
+
"Ap,LocalBoot",
|
|
270
|
+
"Ap,LocalPolicy",
|
|
271
|
+
"Ap,NextStageIM4MHash",
|
|
272
|
+
"Ap,RecoveryOSPolicyNonceHash",
|
|
273
|
+
"Ap,VolumeUUID",
|
|
274
|
+
"ApECID",
|
|
275
|
+
"ApChipID",
|
|
276
|
+
"ApBoardID",
|
|
277
|
+
"ApSecurityDomain",
|
|
278
|
+
"ApNonce",
|
|
279
|
+
"ApSecurityMode",
|
|
280
|
+
"ApProductionMode",
|
|
281
|
+
)
|
|
237
282
|
|
|
238
283
|
for k in keys_to_copy:
|
|
239
284
|
if k in parameters:
|
|
240
285
|
v = parameters[k]
|
|
241
|
-
if isinstance(v, str) and v.startswith(
|
|
286
|
+
if isinstance(v, str) and v.startswith("0x"):
|
|
242
287
|
v = int(v, 16)
|
|
243
288
|
self._request[k] = v
|
|
244
289
|
|
|
245
290
|
def add_vinyl_tags(self, parameters: dict, overrides=None):
|
|
246
|
-
self._request[
|
|
291
|
+
self._request["@BBTicket"] = True
|
|
292
|
+
self._request["@eUICC,Ticket"] = True
|
|
247
293
|
|
|
248
|
-
self._request[
|
|
249
|
-
|
|
294
|
+
self._request["eUICC,ApProductionMode"] = parameters.get(
|
|
295
|
+
"eUICC,ApProductionMode", parameters.get("ApProductionMode")
|
|
296
|
+
)
|
|
250
297
|
|
|
251
|
-
keys = (
|
|
298
|
+
keys = ("eUICC,ChipID", "eUICC,EID", "eUICC,RootKeyIdentifier")
|
|
252
299
|
for k in keys:
|
|
253
300
|
if k in parameters:
|
|
254
301
|
self._request[k] = parameters[k]
|
|
255
302
|
|
|
256
|
-
if self._request.get(
|
|
257
|
-
n = plist_access_path(parameters, (
|
|
303
|
+
if self._request.get("eUICC,Gold") is None:
|
|
304
|
+
n = plist_access_path(parameters, ("Manifest", "eUICC,Gold"))
|
|
258
305
|
if n:
|
|
259
|
-
self._request[
|
|
306
|
+
self._request["eUICC,Gold"] = {"Digest": n["Digest"]}
|
|
260
307
|
|
|
261
|
-
if self._request.get(
|
|
262
|
-
n = plist_access_path(parameters, (
|
|
308
|
+
if self._request.get("eUICC,Main") is None:
|
|
309
|
+
n = plist_access_path(parameters, ("Manifest", "eUICC,Main"))
|
|
263
310
|
if n:
|
|
264
|
-
self._request[
|
|
311
|
+
self._request["eUICC,Main"] = {"Digest": n["Digest"]}
|
|
265
312
|
|
|
266
313
|
# set Nonce for eUICC,Gold component
|
|
267
|
-
node = parameters.get(
|
|
314
|
+
node = parameters.get("EUICCGoldNonce")
|
|
268
315
|
if node is not None:
|
|
269
|
-
n = self._request.get(
|
|
316
|
+
n = self._request.get("eUICC,Gold")
|
|
270
317
|
if n is not None:
|
|
271
|
-
n[
|
|
318
|
+
n["Nonce"] = node
|
|
272
319
|
|
|
273
320
|
# set Nonce for eUICC,Main component
|
|
274
|
-
node = parameters.get(
|
|
321
|
+
node = parameters.get("EUICCMainNonce")
|
|
275
322
|
if node is not None:
|
|
276
|
-
n = self._request.get(
|
|
323
|
+
n = self._request.get("eUICC,Main")
|
|
277
324
|
if n is not None:
|
|
278
|
-
n[
|
|
325
|
+
n["Nonce"] = node
|
|
279
326
|
|
|
280
327
|
if overrides is not None:
|
|
281
328
|
self._request.update(overrides)
|
|
282
329
|
|
|
283
330
|
def add_ap_tags(self, parameters: dict, overrides=None):
|
|
284
|
-
"""
|
|
331
|
+
"""loop over components from build manifest"""
|
|
285
332
|
|
|
286
|
-
manifest_node = parameters[
|
|
333
|
+
manifest_node = parameters["Manifest"]
|
|
287
334
|
|
|
288
335
|
# add components to request
|
|
289
|
-
skipped_keys = (
|
|
336
|
+
skipped_keys = ("BasebandFirmware", "SE,UpdatePayload", "BaseSystem", "Diags", "Ap,ExclaveOS")
|
|
290
337
|
for key, manifest_entry in manifest_node.items():
|
|
291
338
|
if key in skipped_keys:
|
|
292
339
|
continue
|
|
293
340
|
|
|
294
|
-
if key.startswith(
|
|
341
|
+
if key.startswith("Cryptex1,"):
|
|
295
342
|
continue
|
|
296
343
|
|
|
297
|
-
info_dict = manifest_entry.get(
|
|
344
|
+
info_dict = manifest_entry.get("Info")
|
|
298
345
|
if info_dict is None:
|
|
299
346
|
continue
|
|
300
347
|
|
|
301
|
-
if parameters.get(
|
|
348
|
+
if parameters.get("ApSupportsImg4", False) and ("RestoreRequestRules" not in info_dict):
|
|
302
349
|
logger.debug(f'Skipping "{key}" as it doesn\'t have RestoreRequestRules')
|
|
303
350
|
continue
|
|
304
351
|
|
|
305
|
-
if parameters.get(
|
|
306
|
-
if not manifest_node.get(
|
|
307
|
-
logger.debug(f
|
|
352
|
+
if parameters.get("_OnlyFWComponents", False):
|
|
353
|
+
if not manifest_node.get("Trusted", False):
|
|
354
|
+
logger.debug(f"skipping {key} as it is not trusted")
|
|
308
355
|
continue
|
|
309
|
-
info = manifest_entry[
|
|
356
|
+
info = manifest_entry["Info"]
|
|
310
357
|
if not is_fw_payload(info):
|
|
311
|
-
logger.debug(f
|
|
358
|
+
logger.debug(f"skipping {key} as it is not a firmware payload")
|
|
312
359
|
continue
|
|
313
360
|
|
|
314
|
-
if info_dict.get(
|
|
315
|
-
logger.debug(
|
|
361
|
+
if info_dict.get("IsFTAB"):
|
|
362
|
+
logger.debug("Skipping IsFTAB")
|
|
316
363
|
continue
|
|
317
364
|
|
|
318
365
|
# copy this entry
|
|
319
366
|
tss_entry = dict(manifest_entry)
|
|
320
367
|
|
|
321
368
|
# remove obsolete Info node
|
|
322
|
-
tss_entry.pop(
|
|
369
|
+
tss_entry.pop("Info")
|
|
323
370
|
|
|
324
371
|
# handle RestoreRequestRules
|
|
325
|
-
if
|
|
326
|
-
rules = manifest_entry[
|
|
372
|
+
if "Info" in manifest_entry and "RestoreRequestRules" in manifest_entry["Info"]:
|
|
373
|
+
rules = manifest_entry["Info"]["RestoreRequestRules"]
|
|
327
374
|
if rules:
|
|
328
|
-
logger.debug(f
|
|
375
|
+
logger.debug(f"Applying restore request rules for entry {key}")
|
|
329
376
|
tss_entry = self.apply_restore_request_rules(tss_entry, parameters, rules)
|
|
330
377
|
|
|
331
378
|
# Make sure we have a Digest key for Trusted items even if empty
|
|
332
|
-
node = manifest_entry.get(
|
|
333
|
-
if node:
|
|
334
|
-
|
|
335
|
-
tss_entry['Digest'] = b''
|
|
379
|
+
node = manifest_entry.get("Trusted", False)
|
|
380
|
+
if node and manifest_entry.get("Digest") is None:
|
|
381
|
+
tss_entry["Digest"] = b""
|
|
336
382
|
|
|
337
383
|
self._request[key] = tss_entry
|
|
338
384
|
|
|
@@ -340,82 +386,115 @@ class TSSRequest:
|
|
|
340
386
|
self._request.update(overrides)
|
|
341
387
|
|
|
342
388
|
def add_ap_img3_tags(self, parameters: dict):
|
|
343
|
-
if
|
|
344
|
-
self._request[
|
|
345
|
-
self._request[
|
|
389
|
+
if "ApNonce" in parameters:
|
|
390
|
+
self._request["ApNonce"] = parameters["ApNonce"]
|
|
391
|
+
self._request["@APTicket"] = True
|
|
346
392
|
|
|
347
393
|
def add_ap_img4_tags(self, parameters):
|
|
348
394
|
keys_to_copy = (
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
395
|
+
"ApNonce",
|
|
396
|
+
"ApProductionMode",
|
|
397
|
+
"ApSecurityMode",
|
|
398
|
+
"Ap,OSLongVersion",
|
|
399
|
+
"ApSecurityMode",
|
|
400
|
+
"ApSepNonce",
|
|
401
|
+
"Ap,SDKPlatform",
|
|
402
|
+
"PearlCertificationRootPub",
|
|
403
|
+
"NeRDEpoch",
|
|
404
|
+
"ApSikaFuse",
|
|
405
|
+
"Ap,SikaFuse",
|
|
406
|
+
"Ap,OSReleaseType",
|
|
407
|
+
"Ap,ProductType",
|
|
408
|
+
"Ap,Target",
|
|
409
|
+
"Ap,TargetType",
|
|
410
|
+
"AllowNeRDBoot",
|
|
411
|
+
"Ap,ProductMarketingVersion",
|
|
412
|
+
"Ap,Timestamp",
|
|
352
413
|
)
|
|
353
414
|
for k in keys_to_copy:
|
|
354
415
|
if k in parameters:
|
|
355
416
|
v = parameters[k]
|
|
356
|
-
if k ==
|
|
357
|
-
k =
|
|
358
|
-
if k ==
|
|
359
|
-
k =
|
|
417
|
+
if k == "ApSepNonce":
|
|
418
|
+
k = "SepNonce"
|
|
419
|
+
if k == "ApSikaFuse":
|
|
420
|
+
k = "Ap,SikaFuse"
|
|
360
421
|
self._request[k] = v
|
|
361
422
|
|
|
362
|
-
uid_mode = parameters.get(
|
|
423
|
+
uid_mode = parameters.get("UID_MODE")
|
|
424
|
+
|
|
425
|
+
if "NeRDEpoch" in parameters:
|
|
426
|
+
self._request["PermitNeRDPivot"] = b""
|
|
427
|
+
|
|
428
|
+
if uid_mode is not None:
|
|
429
|
+
self._request["UID_MODE"] = uid_mode
|
|
430
|
+
self._request["@ApImg4Ticket"] = True
|
|
431
|
+
self._request["@BBTicket"] = True
|
|
363
432
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
433
|
+
if parameters.get("RequiresUIDMode"):
|
|
434
|
+
# The logic here is missing why this value is expected to be 'false'
|
|
435
|
+
self._request["UID_MODE"] = False
|
|
367
436
|
|
|
368
|
-
|
|
369
|
-
self._request[
|
|
437
|
+
# Workaround: We have only seen Ap,SikaFuse together with UID_MODE
|
|
438
|
+
self._request["Ap,SikaFuse"] = 0
|
|
370
439
|
|
|
371
440
|
def add_se_tags(self, parameters: dict, overrides=None):
|
|
372
|
-
manifest = parameters[
|
|
441
|
+
manifest = parameters["Manifest"]
|
|
373
442
|
|
|
374
443
|
# add tags indicating we want to get the SE,Ticket
|
|
375
|
-
self._request[
|
|
376
|
-
self._request[
|
|
444
|
+
self._request["@BBTicket"] = True
|
|
445
|
+
self._request["@SE,Ticket"] = True
|
|
377
446
|
|
|
378
|
-
keys_to_copy = (
|
|
379
|
-
|
|
447
|
+
keys_to_copy = (
|
|
448
|
+
"SE,ChipID",
|
|
449
|
+
"SE,ID",
|
|
450
|
+
"SE,Nonce",
|
|
451
|
+
"SE,Nonce",
|
|
452
|
+
"SE,RootKeyIdentifier",
|
|
453
|
+
"SEChipID",
|
|
454
|
+
"SEID",
|
|
455
|
+
"SENonce",
|
|
456
|
+
"SENonce",
|
|
457
|
+
"SERootKeyIdentifier",
|
|
458
|
+
)
|
|
380
459
|
|
|
381
460
|
for src_key in keys_to_copy:
|
|
382
461
|
if src_key not in parameters:
|
|
383
462
|
continue
|
|
384
463
|
|
|
385
|
-
if src_key.startswith(
|
|
464
|
+
if src_key.startswith("SE"):
|
|
386
465
|
dst_key = src_key
|
|
387
|
-
if not dst_key.startswith(
|
|
466
|
+
if not dst_key.startswith("SE,"):
|
|
388
467
|
# make sure there is a comma (,) after prefix
|
|
389
|
-
dst_key =
|
|
468
|
+
dst_key = "SE," + dst_key.split("SE", 1)[1]
|
|
390
469
|
self._request[dst_key] = parameters[src_key]
|
|
391
470
|
|
|
392
471
|
# 'IsDev' determines whether we have Production or Development
|
|
393
|
-
is_dev = parameters.get(
|
|
472
|
+
is_dev = parameters.get("SE,IsDev")
|
|
394
473
|
if is_dev is None:
|
|
395
|
-
is_dev = parameters.get(
|
|
474
|
+
is_dev = parameters.get("SEIsDev", False)
|
|
396
475
|
|
|
397
476
|
# add SE,* components from build manifest to request
|
|
398
477
|
for key, manifest_entry in manifest.items():
|
|
399
|
-
if not key.startswith(
|
|
478
|
+
if not key.startswith("SE"):
|
|
400
479
|
continue
|
|
401
480
|
|
|
402
481
|
# copy this entry
|
|
403
482
|
tss_entry = dict(manifest_entry)
|
|
404
483
|
|
|
405
484
|
# remove Info node
|
|
406
|
-
tss_entry.pop(
|
|
485
|
+
tss_entry.pop("Info")
|
|
407
486
|
|
|
408
487
|
# remove Development or Production key/hash node
|
|
409
488
|
if is_dev:
|
|
410
|
-
if
|
|
411
|
-
tss_entry.pop(
|
|
412
|
-
if
|
|
413
|
-
tss_entry.pop(
|
|
489
|
+
if "ProductionCMAC" in tss_entry:
|
|
490
|
+
tss_entry.pop("ProductionCMAC")
|
|
491
|
+
if "ProductionUpdatePayloadHash" in tss_entry:
|
|
492
|
+
tss_entry.pop("ProductionUpdatePayloadHash")
|
|
414
493
|
else:
|
|
415
|
-
if
|
|
416
|
-
tss_entry.pop(
|
|
417
|
-
if
|
|
418
|
-
tss_entry.pop(
|
|
494
|
+
if "DevelopmentCMAC" in tss_entry:
|
|
495
|
+
tss_entry.pop("DevelopmentCMAC")
|
|
496
|
+
if "DevelopmentUpdatePayloadHash" in tss_entry:
|
|
497
|
+
tss_entry.pop("DevelopmentUpdatePayloadHash")
|
|
419
498
|
|
|
420
499
|
# add entry to request
|
|
421
500
|
self._request[key] = tss_entry
|
|
@@ -424,21 +503,27 @@ class TSSRequest:
|
|
|
424
503
|
self._request.update(overrides)
|
|
425
504
|
|
|
426
505
|
def add_savage_tags(self, parameters: dict, overrides=None, component_name=None):
|
|
427
|
-
manifest = parameters[
|
|
506
|
+
manifest = parameters["Manifest"]
|
|
428
507
|
|
|
429
508
|
# add tags indicating we want to get the Savage,Ticket
|
|
430
|
-
self._request[
|
|
431
|
-
self._request[
|
|
509
|
+
self._request["@BBTicket"] = True
|
|
510
|
+
self._request["@Savage,Ticket"] = True
|
|
432
511
|
|
|
433
512
|
# add Savage,UID
|
|
434
|
-
self._request[
|
|
513
|
+
self._request["Savage,UID"] = get_with_or_without_comma(parameters, "Savage,UID")
|
|
435
514
|
|
|
436
515
|
# add SEP
|
|
437
|
-
self._request[
|
|
516
|
+
self._request["SEP"] = {"Digest": manifest["SEP"]["Digest"]}
|
|
438
517
|
|
|
439
518
|
keys_to_copy = (
|
|
440
|
-
|
|
441
|
-
|
|
519
|
+
"Savage,PatchEpoch",
|
|
520
|
+
"Savage,ChipID",
|
|
521
|
+
"Savage,AllowOfflineBoot",
|
|
522
|
+
"Savage,ReadFWKey",
|
|
523
|
+
"Savage,ProductionMode",
|
|
524
|
+
"Savage,Nonce",
|
|
525
|
+
"Savage,Nonce",
|
|
526
|
+
)
|
|
442
527
|
|
|
443
528
|
for k in keys_to_copy:
|
|
444
529
|
value = get_with_or_without_comma(parameters, k)
|
|
@@ -446,22 +531,22 @@ class TSSRequest:
|
|
|
446
531
|
continue
|
|
447
532
|
self._request[k] = value
|
|
448
533
|
|
|
449
|
-
isprod = get_with_or_without_comma(parameters,
|
|
534
|
+
isprod = get_with_or_without_comma(parameters, "Savage,ProductionMode")
|
|
450
535
|
|
|
451
536
|
# get the right component name
|
|
452
|
-
comp_name =
|
|
453
|
-
node = get_with_or_without_comma(parameters,
|
|
537
|
+
comp_name = "Savage,B0-Prod-Patch" if isprod else "Savage,B0-Dev-Patch"
|
|
538
|
+
node = get_with_or_without_comma(parameters, "Savage,Revision")
|
|
454
539
|
|
|
455
540
|
if isinstance(node, bytes):
|
|
456
541
|
savage_rev = node
|
|
457
542
|
if ((savage_rev[0] | 0x10) & 0xF0) == 0x30:
|
|
458
|
-
comp_name =
|
|
543
|
+
comp_name = "Savage,B2-Prod-Patch" if isprod else "Savage,B2-Dev-Patch"
|
|
459
544
|
elif (savage_rev[0] & 0xF0) == 0xA0:
|
|
460
|
-
comp_name =
|
|
545
|
+
comp_name = "Savage,BA-Prod-Patch" if isprod else "Savage,BA-Dev-Patch"
|
|
461
546
|
|
|
462
547
|
# add Savage,B?-*-Patch
|
|
463
548
|
d = dict(manifest[comp_name])
|
|
464
|
-
d.pop(
|
|
549
|
+
d.pop("Info")
|
|
465
550
|
self._request[comp_name] = d
|
|
466
551
|
|
|
467
552
|
if overrides is not None:
|
|
@@ -470,36 +555,44 @@ class TSSRequest:
|
|
|
470
555
|
return comp_name
|
|
471
556
|
|
|
472
557
|
def add_yonkers_tags(self, parameters: dict, overrides=None):
|
|
473
|
-
manifest = parameters[
|
|
558
|
+
manifest = parameters["Manifest"]
|
|
474
559
|
|
|
475
560
|
# add tags indicating we want to get the Yonkers,Ticket
|
|
476
|
-
self._request[
|
|
477
|
-
self._request[
|
|
561
|
+
self._request["@BBTicket"] = True
|
|
562
|
+
self._request["@Yonkers,Ticket"] = True
|
|
478
563
|
|
|
479
564
|
# add SEP
|
|
480
|
-
self._request[
|
|
565
|
+
self._request["SEP"] = {"Digest": manifest["SEP"]["Digest"]}
|
|
481
566
|
|
|
482
567
|
keys_to_copy = (
|
|
483
|
-
|
|
484
|
-
|
|
568
|
+
"Yonkers,AllowOfflineBoot",
|
|
569
|
+
"Yonkers,BoardID",
|
|
570
|
+
"Yonkers,ChipID",
|
|
571
|
+
"Yonkers,ECID",
|
|
572
|
+
"Yonkers,Nonce",
|
|
573
|
+
"Yonkers,PatchEpoch",
|
|
574
|
+
"Yonkers,ProductionMode",
|
|
575
|
+
"Yonkers,ReadECKey",
|
|
576
|
+
"Yonkers,ReadFWKey",
|
|
577
|
+
)
|
|
485
578
|
|
|
486
579
|
for k in keys_to_copy:
|
|
487
580
|
self._request[k] = get_with_or_without_comma(parameters, k)
|
|
488
581
|
|
|
489
|
-
isprod = get_with_or_without_comma(parameters,
|
|
490
|
-
fabrevision = get_with_or_without_comma(parameters,
|
|
582
|
+
isprod = get_with_or_without_comma(parameters, "Yonkers,ProductionMode", 1)
|
|
583
|
+
fabrevision = get_with_or_without_comma(parameters, "Yonkers,FabRevision", 0xFFFFFFFFFFFFFFFF)
|
|
491
584
|
comp_node = None
|
|
492
585
|
result_comp_name = None
|
|
493
586
|
|
|
494
587
|
for comp_name, node in manifest.items():
|
|
495
|
-
if not comp_name.startswith(
|
|
588
|
+
if not comp_name.startswith("Yonkers,"):
|
|
496
589
|
continue
|
|
497
590
|
|
|
498
591
|
target_node = 1
|
|
499
|
-
sub_node = node.get(
|
|
592
|
+
sub_node = node.get("EPRO")
|
|
500
593
|
if sub_node:
|
|
501
594
|
target_node &= sub_node if isprod else not sub_node
|
|
502
|
-
sub_node = node.get(
|
|
595
|
+
sub_node = node.get("FabRevision")
|
|
503
596
|
if sub_node:
|
|
504
597
|
target_node &= sub_node == fabrevision
|
|
505
598
|
|
|
@@ -509,11 +602,11 @@ class TSSRequest:
|
|
|
509
602
|
break
|
|
510
603
|
|
|
511
604
|
if comp_node is None:
|
|
512
|
-
raise PyMobileDevice3Exception(f
|
|
605
|
+
raise PyMobileDevice3Exception(f"No Yonkers node for {isprod}/{fabrevision}")
|
|
513
606
|
|
|
514
607
|
# add Yonkers,SysTopPatch
|
|
515
608
|
comp_dict = dict(comp_node)
|
|
516
|
-
comp_dict.pop(
|
|
609
|
+
comp_dict.pop("Info")
|
|
517
610
|
self._request[result_comp_name] = comp_dict
|
|
518
611
|
|
|
519
612
|
if overrides is not None:
|
|
@@ -522,45 +615,60 @@ class TSSRequest:
|
|
|
522
615
|
return result_comp_name
|
|
523
616
|
|
|
524
617
|
def add_baseband_tags(self, parameters: dict, overrides=None):
|
|
525
|
-
self._request[
|
|
618
|
+
self._request["@BBTicket"] = True
|
|
526
619
|
|
|
527
620
|
keys_to_copy = (
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
621
|
+
"BbChipID",
|
|
622
|
+
"BbProvisioningManifestKeyHash",
|
|
623
|
+
"BbActivationManifestKeyHash",
|
|
624
|
+
"BbCalibrationManifestKeyHash",
|
|
625
|
+
"BbFactoryActivationManifestKeyHash",
|
|
626
|
+
"BbFDRSecurityKeyHash",
|
|
627
|
+
"BbSkeyId",
|
|
628
|
+
"BbNonce",
|
|
629
|
+
"BbGoldCertId",
|
|
630
|
+
"BbSNUM",
|
|
631
|
+
"PearlCertificationRootPub",
|
|
632
|
+
"Ap,OSLongVersion",
|
|
633
|
+
)
|
|
531
634
|
|
|
532
635
|
for k in keys_to_copy:
|
|
533
636
|
if k in parameters:
|
|
534
637
|
self._request[k] = parameters[k]
|
|
535
638
|
|
|
536
|
-
bb_chip_id = parameters[
|
|
537
|
-
bb_cert_id = parameters[
|
|
639
|
+
bb_chip_id = parameters["BbChipID"]
|
|
640
|
+
bb_cert_id = parameters["BbGoldCertId"]
|
|
538
641
|
|
|
539
|
-
bbfwdict = dict(parameters[
|
|
540
|
-
bbfwdict.pop(
|
|
642
|
+
bbfwdict = dict(parameters["Manifest"]["BasebandFirmware"])
|
|
643
|
+
bbfwdict.pop("Info")
|
|
541
644
|
|
|
542
645
|
if bb_chip_id == 0x68:
|
|
543
646
|
# depending on the BasebandCertId remove certain nodes
|
|
544
647
|
if bb_cert_id in (0x26F3FACC, 0x5CF2EC4E, 0x8399785A):
|
|
545
|
-
bbfwdict.pop(
|
|
546
|
-
bbfwdict.pop(
|
|
648
|
+
bbfwdict.pop("PSI2-PartialDigest")
|
|
649
|
+
bbfwdict.pop("RestorePSI2-PartialDigest")
|
|
547
650
|
else:
|
|
548
|
-
bbfwdict.pop(
|
|
549
|
-
bbfwdict.pop(
|
|
651
|
+
bbfwdict.pop("PSI-PartialDigest")
|
|
652
|
+
bbfwdict.pop("RestorePSI-PartialDigest")
|
|
550
653
|
|
|
551
|
-
self._request[
|
|
654
|
+
self._request["BasebandFirmware"] = bbfwdict
|
|
552
655
|
|
|
553
656
|
if overrides:
|
|
554
657
|
self._request.update(overrides)
|
|
555
658
|
|
|
556
659
|
def add_rose_tags(self, parameters: dict, overrides: typing.Optional[dict] = None):
|
|
557
|
-
manifest = parameters[
|
|
660
|
+
manifest = parameters["Manifest"]
|
|
558
661
|
|
|
559
662
|
# add tags indicating we want to get the Rap,Ticket
|
|
560
|
-
self._request[
|
|
561
|
-
self._request[
|
|
562
|
-
|
|
563
|
-
keys_to_copy_uint = (
|
|
663
|
+
self._request["@BBTicket"] = True
|
|
664
|
+
self._request["@Rap,Ticket"] = True
|
|
665
|
+
|
|
666
|
+
keys_to_copy_uint = (
|
|
667
|
+
"Rap,BoardID",
|
|
668
|
+
"Rap,ChipID",
|
|
669
|
+
"Rap,ECID",
|
|
670
|
+
"Rap,SecurityDomain",
|
|
671
|
+
)
|
|
564
672
|
|
|
565
673
|
for key in keys_to_copy_uint:
|
|
566
674
|
value = get_with_or_without_comma(parameters, key)
|
|
@@ -570,41 +678,44 @@ class TSSRequest:
|
|
|
570
678
|
else:
|
|
571
679
|
self._request[key] = value
|
|
572
680
|
|
|
573
|
-
keys_to_copy_bool = (
|
|
681
|
+
keys_to_copy_bool = (
|
|
682
|
+
"Rap,ProductionMode",
|
|
683
|
+
"Rap,SecurityMode",
|
|
684
|
+
)
|
|
574
685
|
|
|
575
686
|
for key in keys_to_copy_bool:
|
|
576
687
|
value = get_with_or_without_comma(parameters, key)
|
|
577
688
|
self._request[key] = bytes_to_uint(value) == 1
|
|
578
689
|
|
|
579
|
-
nonce = get_with_or_without_comma(parameters,
|
|
690
|
+
nonce = get_with_or_without_comma(parameters, "Rap,Nonce")
|
|
580
691
|
if nonce is not None:
|
|
581
|
-
self._request[
|
|
692
|
+
self._request["Rap,Nonce"] = nonce
|
|
582
693
|
|
|
583
|
-
digest = get_with_or_without_comma(parameters,
|
|
694
|
+
digest = get_with_or_without_comma(parameters, "Rap,FdrRootCaDigest")
|
|
584
695
|
if digest is not None:
|
|
585
|
-
self._request[
|
|
696
|
+
self._request["Rap,FdrRootCaDigest"] = digest
|
|
586
697
|
|
|
587
698
|
for comp_name, node in manifest.items():
|
|
588
|
-
if not comp_name.startswith(
|
|
699
|
+
if not comp_name.startswith("Rap,"):
|
|
589
700
|
continue
|
|
590
701
|
|
|
591
702
|
manifest_entry = dict(node)
|
|
592
703
|
|
|
593
704
|
# handle RestoreRequestRules
|
|
594
|
-
rules = manifest_entry[
|
|
705
|
+
rules = manifest_entry["Info"].get("RestoreRequestRules")
|
|
595
706
|
if rules is not None:
|
|
596
707
|
self.apply_restore_request_rules(manifest_entry, parameters, rules)
|
|
597
708
|
|
|
598
709
|
# Make sure we have a Digest key for Trusted items even if empty
|
|
599
|
-
trusted = manifest_entry.get(
|
|
710
|
+
trusted = manifest_entry.get("Trusted", False)
|
|
600
711
|
|
|
601
712
|
if trusted:
|
|
602
|
-
digest = manifest_entry.get(
|
|
713
|
+
digest = manifest_entry.get("Digest")
|
|
603
714
|
if digest is None:
|
|
604
|
-
logger.debug(f
|
|
605
|
-
manifest_entry[
|
|
715
|
+
logger.debug(f"No Digest data, using empty value for entry {comp_name}")
|
|
716
|
+
manifest_entry["Digest"] = b""
|
|
606
717
|
|
|
607
|
-
manifest_entry.pop(
|
|
718
|
+
manifest_entry.pop("Info")
|
|
608
719
|
|
|
609
720
|
# finally add entry to request
|
|
610
721
|
self._request[comp_name] = manifest_entry
|
|
@@ -613,41 +724,41 @@ class TSSRequest:
|
|
|
613
724
|
self._request.update(overrides)
|
|
614
725
|
|
|
615
726
|
def add_veridian_tags(self, parameters: dict, overrides: typing.Optional[dict] = None):
|
|
616
|
-
manifest = parameters[
|
|
727
|
+
manifest = parameters["Manifest"]
|
|
617
728
|
|
|
618
729
|
# add tags indicating we want to get the Rap,Ticket
|
|
619
|
-
self._request[
|
|
620
|
-
self._request[
|
|
730
|
+
self._request["@BBTicket"] = True
|
|
731
|
+
self._request["@BMU,Ticket"] = True
|
|
621
732
|
|
|
622
|
-
self._request[
|
|
623
|
-
self._request[
|
|
624
|
-
self._request[
|
|
733
|
+
self._request["BMU,ChipID"] = parameters["ChipID"]
|
|
734
|
+
self._request["BMU,UniqueID"] = parameters["UniqueID"]
|
|
735
|
+
self._request["BMU,ProductionMode"] = parameters["ProductionMode"]
|
|
625
736
|
|
|
626
|
-
nonce = parameters.get(
|
|
737
|
+
nonce = parameters.get("Nonce")
|
|
627
738
|
if nonce is not None:
|
|
628
|
-
self._request[
|
|
739
|
+
self._request["BMU,Nonce"] = nonce
|
|
629
740
|
|
|
630
741
|
for comp_name, node in manifest.items():
|
|
631
|
-
if not comp_name.startswith(
|
|
742
|
+
if not comp_name.startswith("BMU,"):
|
|
632
743
|
continue
|
|
633
744
|
|
|
634
745
|
manifest_entry = dict(node)
|
|
635
746
|
|
|
636
747
|
# handle RestoreRequestRules
|
|
637
|
-
rules = manifest_entry[
|
|
748
|
+
rules = manifest_entry["Info"].get("RestoreRequestRules")
|
|
638
749
|
if rules is not None:
|
|
639
750
|
self.apply_restore_request_rules(manifest_entry, parameters, rules)
|
|
640
751
|
|
|
641
752
|
# Make sure we have a Digest key for Trusted items even if empty
|
|
642
|
-
trusted = manifest_entry.get(
|
|
753
|
+
trusted = manifest_entry.get("Trusted", False)
|
|
643
754
|
|
|
644
755
|
if trusted:
|
|
645
|
-
digest = manifest_entry.get(
|
|
756
|
+
digest = manifest_entry.get("Digest")
|
|
646
757
|
if digest is None:
|
|
647
|
-
logger.debug(f
|
|
648
|
-
manifest_entry[
|
|
758
|
+
logger.debug(f"No Digest data, using empty value for entry {comp_name}")
|
|
759
|
+
manifest_entry["Digest"] = b""
|
|
649
760
|
|
|
650
|
-
manifest_entry.pop(
|
|
761
|
+
manifest_entry.pop("Info")
|
|
651
762
|
|
|
652
763
|
# finally add entry to request
|
|
653
764
|
self._request[comp_name] = manifest_entry
|
|
@@ -656,14 +767,19 @@ class TSSRequest:
|
|
|
656
767
|
self._request.update(overrides)
|
|
657
768
|
|
|
658
769
|
def add_tcon_tags(self, parameters: dict, overrides: typing.Optional[dict] = None):
|
|
659
|
-
manifest = parameters[
|
|
770
|
+
manifest = parameters["Manifest"]
|
|
660
771
|
|
|
661
772
|
# add tags indicating we want to get the Baobab,Ticket
|
|
662
|
-
self._request[
|
|
663
|
-
self._request[
|
|
664
|
-
|
|
665
|
-
keys_to_copy_uint = (
|
|
666
|
-
|
|
773
|
+
self._request["@BBTicket"] = True
|
|
774
|
+
self._request["@Baobab,Ticket"] = True
|
|
775
|
+
|
|
776
|
+
keys_to_copy_uint = (
|
|
777
|
+
"Baobab,BoardID",
|
|
778
|
+
"Baobab,ChipID",
|
|
779
|
+
"Baobab,Life",
|
|
780
|
+
"Baobab,ManifestEpoch",
|
|
781
|
+
"Baobab,SecurityDomain",
|
|
782
|
+
)
|
|
667
783
|
|
|
668
784
|
for key in keys_to_copy_uint:
|
|
669
785
|
value = get_with_or_without_comma(parameters, key)
|
|
@@ -673,26 +789,26 @@ class TSSRequest:
|
|
|
673
789
|
else:
|
|
674
790
|
self._request[key] = value
|
|
675
791
|
|
|
676
|
-
isprod = bool(get_with_or_without_comma(parameters,
|
|
677
|
-
self._request[
|
|
792
|
+
isprod = bool(get_with_or_without_comma(parameters, "Baobab,ProductionMode", False))
|
|
793
|
+
self._request["Baobab,ProductionMode"] = isprod
|
|
678
794
|
|
|
679
|
-
nonce = get_with_or_without_comma(parameters,
|
|
795
|
+
nonce = get_with_or_without_comma(parameters, "Baobab,UpdateNonce")
|
|
680
796
|
|
|
681
797
|
if nonce is not None:
|
|
682
|
-
self._request[
|
|
798
|
+
self._request["Baobab,UpdateNonce"] = nonce
|
|
683
799
|
|
|
684
|
-
ecid = get_with_or_without_comma(parameters,
|
|
800
|
+
ecid = get_with_or_without_comma(parameters, "Baobab,ECID")
|
|
685
801
|
|
|
686
802
|
if ecid is not None:
|
|
687
|
-
self._request[
|
|
803
|
+
self._request["Baobab,ECID"] = ecid
|
|
688
804
|
|
|
689
805
|
for comp_name, node in manifest.items():
|
|
690
|
-
if not comp_name.startswith(
|
|
806
|
+
if not comp_name.startswith("Baobab,"):
|
|
691
807
|
continue
|
|
692
808
|
|
|
693
809
|
manifest_entry = dict(node)
|
|
694
|
-
manifest_entry.pop(
|
|
695
|
-
manifest_entry[
|
|
810
|
+
manifest_entry.pop("Info")
|
|
811
|
+
manifest_entry["EPRO"] = isprod
|
|
696
812
|
|
|
697
813
|
# finally add entry to request
|
|
698
814
|
self._request[comp_name] = manifest_entry
|
|
@@ -703,31 +819,31 @@ class TSSRequest:
|
|
|
703
819
|
def img4_create_local_manifest(self, build_identity=None):
|
|
704
820
|
manifest = None
|
|
705
821
|
if build_identity is not None:
|
|
706
|
-
manifest = build_identity[
|
|
822
|
+
manifest = build_identity["Manifest"]
|
|
707
823
|
|
|
708
824
|
p = asn1.Encoder()
|
|
709
825
|
p.start()
|
|
710
826
|
|
|
711
|
-
p.write(b
|
|
827
|
+
p.write(b"MANP", asn1.Numbers.IA5String)
|
|
712
828
|
p.enter(asn1.Numbers.Set)
|
|
713
829
|
|
|
714
|
-
p.write(b
|
|
715
|
-
p.write(self._request[
|
|
830
|
+
p.write(b"BORD", asn1.Numbers.IA5String)
|
|
831
|
+
p.write(self._request["ApBoardID"], asn1.Numbers.Integer)
|
|
716
832
|
|
|
717
|
-
p.write(b
|
|
833
|
+
p.write(b"CEPO", asn1.Numbers.IA5String)
|
|
718
834
|
p.write(0, asn1.Numbers.Integer)
|
|
719
835
|
|
|
720
|
-
p.write(b
|
|
721
|
-
p.write(self._request[
|
|
836
|
+
p.write(b"CHIP", asn1.Numbers.IA5String)
|
|
837
|
+
p.write(self._request["ApChipID"], asn1.Numbers.Integer)
|
|
722
838
|
|
|
723
|
-
p.write(b
|
|
724
|
-
p.write(self._request[
|
|
839
|
+
p.write(b"CPRO", asn1.Numbers.IA5String)
|
|
840
|
+
p.write(self._request["ApProductionMode"], asn1.Numbers.Integer)
|
|
725
841
|
|
|
726
|
-
p.write(b
|
|
842
|
+
p.write(b"CSEC", asn1.Numbers.IA5String)
|
|
727
843
|
p.write(0, asn1.Numbers.Integer)
|
|
728
844
|
|
|
729
|
-
p.write(b
|
|
730
|
-
p.write(self._request[
|
|
845
|
+
p.write(b"SDOM", asn1.Numbers.IA5String)
|
|
846
|
+
p.write(self._request["ApSecurityDomain"], asn1.Numbers.Integer)
|
|
731
847
|
|
|
732
848
|
p.leave()
|
|
733
849
|
|
|
@@ -737,23 +853,23 @@ class TSSRequest:
|
|
|
737
853
|
# check if component has Img4PayloadType
|
|
738
854
|
comp = None
|
|
739
855
|
if manifest is not None:
|
|
740
|
-
comp = manifest[k][
|
|
856
|
+
comp = manifest[k]["Info"].get("Img4PayloadType")
|
|
741
857
|
|
|
742
858
|
if comp is None:
|
|
743
859
|
comp = COMPONENT_FOURCC.get(k)
|
|
744
860
|
|
|
745
861
|
if comp is None:
|
|
746
|
-
raise NotImplementedError(f
|
|
862
|
+
raise NotImplementedError(f"Unhandled component {k} - can't create manifest")
|
|
747
863
|
|
|
748
|
-
logger.debug(f
|
|
864
|
+
logger.debug(f"found component {comp} ({k})")
|
|
749
865
|
|
|
750
866
|
# write manifest body header
|
|
751
|
-
p.write(b
|
|
867
|
+
p.write(b"MANB", asn1.Numbers.IA5String)
|
|
752
868
|
p.enter(asn1.Numbers.Set)
|
|
753
869
|
p.leave()
|
|
754
870
|
|
|
755
871
|
# write header values
|
|
756
|
-
p.write(b
|
|
872
|
+
p.write(b"IM4M", asn1.Numbers.IA5String)
|
|
757
873
|
p.write(0, asn1.Numbers.Integer)
|
|
758
874
|
|
|
759
875
|
return p.output()
|
|
@@ -767,28 +883,30 @@ class TSSRequest:
|
|
|
767
883
|
|
|
768
884
|
async def send_receive(self) -> TSSResponse:
|
|
769
885
|
headers = {
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
886
|
+
"Cache-Control": "no-cache",
|
|
887
|
+
"Content-type": 'text/xml; charset="utf-8"',
|
|
888
|
+
"User-Agent": "InetURL/1.0",
|
|
889
|
+
"Expect": "",
|
|
774
890
|
}
|
|
775
891
|
|
|
776
|
-
logger.info(
|
|
892
|
+
logger.info("Sending TSS request...")
|
|
777
893
|
logger.debug(self._request)
|
|
778
894
|
|
|
779
895
|
loop = asyncio.get_event_loop()
|
|
780
896
|
with ThreadPoolExecutor() as executor:
|
|
897
|
+
|
|
781
898
|
def post() -> bytes:
|
|
782
|
-
return requests.post(
|
|
783
|
-
|
|
899
|
+
return requests.post(
|
|
900
|
+
TSS_CONTROLLER_ACTION_URL, headers=headers, data=plistlib.dumps(self._request), verify=False
|
|
901
|
+
).content
|
|
784
902
|
|
|
785
903
|
content = await loop.run_in_executor(executor, post)
|
|
786
904
|
|
|
787
|
-
if b
|
|
788
|
-
logger.info(
|
|
905
|
+
if b"MESSAGE=SUCCESS" in content:
|
|
906
|
+
logger.info("response successfully received")
|
|
789
907
|
|
|
790
|
-
message = content.split(b
|
|
791
|
-
if message !=
|
|
792
|
-
raise
|
|
908
|
+
message = content.split(b"MESSAGE=", 1)[1].split(b"&", 1)[0].decode()
|
|
909
|
+
if message != "SUCCESS":
|
|
910
|
+
raise TSSError(f"server replied: {message}")
|
|
793
911
|
|
|
794
|
-
return TSSResponse(plistlib.loads(content.split(b
|
|
912
|
+
return TSSResponse(plistlib.loads(content.split(b"REQUEST_STRING=", 1)[1]))
|