pymobiledevice3 5.0.1__py3-none-any.whl → 5.0.3__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.
Potentially problematic release.
This version of pymobiledevice3 might be problematic. Click here for more details.
- misc/plist_sniffer.py +15 -15
- misc/remotexpc_sniffer.py +29 -28
- pymobiledevice3/__main__.py +128 -102
- pymobiledevice3/_version.py +2 -2
- pymobiledevice3/bonjour.py +36 -59
- pymobiledevice3/ca.py +32 -24
- pymobiledevice3/cli/activation.py +7 -7
- pymobiledevice3/cli/afc.py +19 -19
- pymobiledevice3/cli/amfi.py +4 -4
- pymobiledevice3/cli/apps.py +51 -39
- pymobiledevice3/cli/backup.py +58 -32
- pymobiledevice3/cli/bonjour.py +25 -18
- pymobiledevice3/cli/cli_common.py +112 -81
- pymobiledevice3/cli/companion_proxy.py +4 -4
- pymobiledevice3/cli/completions.py +10 -10
- pymobiledevice3/cli/crash.py +37 -31
- pymobiledevice3/cli/developer.py +602 -520
- pymobiledevice3/cli/diagnostics.py +38 -33
- pymobiledevice3/cli/lockdown.py +79 -74
- pymobiledevice3/cli/mounter.py +85 -68
- pymobiledevice3/cli/notification.py +10 -10
- pymobiledevice3/cli/pcap.py +19 -14
- pymobiledevice3/cli/power_assertion.py +12 -10
- pymobiledevice3/cli/processes.py +10 -10
- pymobiledevice3/cli/profile.py +88 -77
- pymobiledevice3/cli/provision.py +17 -17
- pymobiledevice3/cli/remote.py +186 -110
- pymobiledevice3/cli/restore.py +43 -40
- pymobiledevice3/cli/springboard.py +30 -28
- pymobiledevice3/cli/syslog.py +85 -58
- pymobiledevice3/cli/usbmux.py +21 -20
- pymobiledevice3/cli/version.py +3 -2
- pymobiledevice3/cli/webinspector.py +157 -79
- pymobiledevice3/common.py +1 -1
- pymobiledevice3/exceptions.py +154 -60
- pymobiledevice3/irecv.py +49 -53
- pymobiledevice3/irecv_devices.py +1489 -492
- pymobiledevice3/lockdown.py +396 -242
- pymobiledevice3/lockdown_service_provider.py +5 -7
- pymobiledevice3/osu/os_utils.py +18 -9
- pymobiledevice3/osu/posix_util.py +28 -15
- pymobiledevice3/osu/win_util.py +14 -8
- pymobiledevice3/pair_records.py +19 -19
- pymobiledevice3/remote/common.py +4 -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 +10 -8
- pymobiledevice3/remote/core_device/file_service.py +47 -33
- pymobiledevice3/remote/remote_service_discovery.py +53 -35
- pymobiledevice3/remote/remotexpc.py +64 -42
- pymobiledevice3/remote/tunnel_service.py +371 -293
- pymobiledevice3/remote/utils.py +12 -11
- pymobiledevice3/remote/xpc_message.py +145 -125
- pymobiledevice3/resources/dsc_uuid_map.py +19 -19
- pymobiledevice3/resources/firmware_notifications.py +16 -16
- pymobiledevice3/restore/asr.py +27 -27
- pymobiledevice3/restore/base_restore.py +90 -47
- pymobiledevice3/restore/consts.py +87 -66
- pymobiledevice3/restore/device.py +11 -11
- pymobiledevice3/restore/fdr.py +46 -46
- pymobiledevice3/restore/ftab.py +19 -19
- pymobiledevice3/restore/img4.py +130 -133
- pymobiledevice3/restore/mbn.py +35 -54
- pymobiledevice3/restore/recovery.py +125 -135
- pymobiledevice3/restore/restore.py +524 -523
- pymobiledevice3/restore/restore_options.py +122 -115
- pymobiledevice3/restore/restored_client.py +25 -22
- pymobiledevice3/restore/tss.py +378 -270
- pymobiledevice3/service_connection.py +50 -46
- pymobiledevice3/services/accessibilityaudit.py +137 -127
- pymobiledevice3/services/afc.py +350 -291
- pymobiledevice3/services/amfi.py +21 -18
- pymobiledevice3/services/companion.py +23 -19
- pymobiledevice3/services/crash_reports.py +60 -46
- pymobiledevice3/services/debugserver_applist.py +3 -3
- pymobiledevice3/services/device_arbitration.py +8 -8
- pymobiledevice3/services/device_link.py +56 -48
- pymobiledevice3/services/diagnostics.py +971 -968
- 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 +442 -421
- pymobiledevice3/services/dvt/instruments/device_info.py +11 -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 +25 -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 +8 -7
- pymobiledevice3/services/house_arrest.py +12 -15
- pymobiledevice3/services/installation_proxy.py +119 -100
- pymobiledevice3/services/lockdown_service.py +12 -5
- pymobiledevice3/services/misagent.py +22 -19
- pymobiledevice3/services/mobile_activation.py +84 -72
- pymobiledevice3/services/mobile_config.py +330 -301
- pymobiledevice3/services/mobile_image_mounter.py +137 -116
- pymobiledevice3/services/mobilebackup2.py +188 -150
- pymobiledevice3/services/notification_proxy.py +11 -11
- pymobiledevice3/services/os_trace.py +69 -51
- pymobiledevice3/services/pcapd.py +306 -306
- pymobiledevice3/services/power_assertion.py +10 -9
- pymobiledevice3/services/preboard.py +4 -4
- pymobiledevice3/services/remote_fetch_symbols.py +16 -14
- pymobiledevice3/services/remote_server.py +176 -146
- pymobiledevice3/services/restore_service.py +16 -16
- pymobiledevice3/services/screenshot.py +13 -10
- 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 +3 -3
- pymobiledevice3/services/web_protocol/automation_session.py +183 -179
- pymobiledevice3/services/web_protocol/cdp_screencast.py +44 -36
- pymobiledevice3/services/web_protocol/cdp_server.py +19 -19
- pymobiledevice3/services/web_protocol/cdp_target.py +411 -373
- pymobiledevice3/services/web_protocol/driver.py +47 -45
- pymobiledevice3/services/web_protocol/element.py +74 -63
- pymobiledevice3/services/web_protocol/inspector_session.py +106 -102
- pymobiledevice3/services/web_protocol/selenium_api.py +3 -3
- pymobiledevice3/services/web_protocol/session_protocol.py +15 -10
- pymobiledevice3/services/web_protocol/switch_to.py +11 -12
- pymobiledevice3/services/webinspector.py +129 -117
- pymobiledevice3/tcp_forwarder.py +35 -22
- pymobiledevice3/tunneld/api.py +20 -15
- pymobiledevice3/tunneld/server.py +212 -133
- pymobiledevice3/usbmux.py +183 -138
- pymobiledevice3/utils.py +14 -11
- {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.3.dist-info}/METADATA +1 -1
- pymobiledevice3-5.0.3.dist-info/RECORD +173 -0
- pymobiledevice3-5.0.1.dist-info/RECORD +0 -173
- {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.3.dist-info}/WHEEL +0 -0
- {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.3.dist-info}/entry_points.txt +0 -0
- {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.3.dist-info}/licenses/LICENSE +0 -0
- {pymobiledevice3-5.0.1.dist-info → pymobiledevice3-5.0.3.dist-info}/top_level.txt +0 -0
pymobiledevice3/restore/tss.py
CHANGED
|
@@ -8,48 +8,54 @@ from uuid import uuid4
|
|
|
8
8
|
import asn1
|
|
9
9
|
import requests
|
|
10
10
|
|
|
11
|
-
from pymobiledevice3.exceptions import PyMobileDevice3Exception
|
|
11
|
+
from pymobiledevice3.exceptions import PyMobileDevice3Exception, TSSError
|
|
12
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
|
|
|
@@ -57,62 +63,57 @@ class TSSResponse(dict):
|
|
|
57
63
|
class TSSRequest:
|
|
58
64
|
def __init__(self):
|
|
59
65
|
self._request: dict[str, typing.Any] = {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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,111 +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[
|
|
247
|
-
self._request[
|
|
291
|
+
self._request["@BBTicket"] = True
|
|
292
|
+
self._request["@eUICC,Ticket"] = True
|
|
248
293
|
|
|
249
|
-
self._request[
|
|
250
|
-
|
|
294
|
+
self._request["eUICC,ApProductionMode"] = parameters.get(
|
|
295
|
+
"eUICC,ApProductionMode", parameters.get("ApProductionMode")
|
|
296
|
+
)
|
|
251
297
|
|
|
252
|
-
keys = (
|
|
298
|
+
keys = ("eUICC,ChipID", "eUICC,EID", "eUICC,RootKeyIdentifier")
|
|
253
299
|
for k in keys:
|
|
254
300
|
if k in parameters:
|
|
255
301
|
self._request[k] = parameters[k]
|
|
256
302
|
|
|
257
|
-
if self._request.get(
|
|
258
|
-
n = plist_access_path(parameters, (
|
|
303
|
+
if self._request.get("eUICC,Gold") is None:
|
|
304
|
+
n = plist_access_path(parameters, ("Manifest", "eUICC,Gold"))
|
|
259
305
|
if n:
|
|
260
|
-
self._request[
|
|
306
|
+
self._request["eUICC,Gold"] = {"Digest": n["Digest"]}
|
|
261
307
|
|
|
262
|
-
if self._request.get(
|
|
263
|
-
n = plist_access_path(parameters, (
|
|
308
|
+
if self._request.get("eUICC,Main") is None:
|
|
309
|
+
n = plist_access_path(parameters, ("Manifest", "eUICC,Main"))
|
|
264
310
|
if n:
|
|
265
|
-
self._request[
|
|
311
|
+
self._request["eUICC,Main"] = {"Digest": n["Digest"]}
|
|
266
312
|
|
|
267
313
|
# set Nonce for eUICC,Gold component
|
|
268
|
-
node = parameters.get(
|
|
314
|
+
node = parameters.get("EUICCGoldNonce")
|
|
269
315
|
if node is not None:
|
|
270
|
-
n = self._request.get(
|
|
316
|
+
n = self._request.get("eUICC,Gold")
|
|
271
317
|
if n is not None:
|
|
272
|
-
n[
|
|
318
|
+
n["Nonce"] = node
|
|
273
319
|
|
|
274
320
|
# set Nonce for eUICC,Main component
|
|
275
|
-
node = parameters.get(
|
|
321
|
+
node = parameters.get("EUICCMainNonce")
|
|
276
322
|
if node is not None:
|
|
277
|
-
n = self._request.get(
|
|
323
|
+
n = self._request.get("eUICC,Main")
|
|
278
324
|
if n is not None:
|
|
279
|
-
n[
|
|
325
|
+
n["Nonce"] = node
|
|
280
326
|
|
|
281
327
|
if overrides is not None:
|
|
282
328
|
self._request.update(overrides)
|
|
283
329
|
|
|
284
330
|
def add_ap_tags(self, parameters: dict, overrides=None):
|
|
285
|
-
"""
|
|
331
|
+
"""loop over components from build manifest"""
|
|
286
332
|
|
|
287
|
-
manifest_node = parameters[
|
|
333
|
+
manifest_node = parameters["Manifest"]
|
|
288
334
|
|
|
289
335
|
# add components to request
|
|
290
|
-
skipped_keys = (
|
|
336
|
+
skipped_keys = ("BasebandFirmware", "SE,UpdatePayload", "BaseSystem", "Diags", "Ap,ExclaveOS")
|
|
291
337
|
for key, manifest_entry in manifest_node.items():
|
|
292
338
|
if key in skipped_keys:
|
|
293
339
|
continue
|
|
294
340
|
|
|
295
|
-
if key.startswith(
|
|
341
|
+
if key.startswith("Cryptex1,"):
|
|
296
342
|
continue
|
|
297
343
|
|
|
298
|
-
info_dict = manifest_entry.get(
|
|
344
|
+
info_dict = manifest_entry.get("Info")
|
|
299
345
|
if info_dict is None:
|
|
300
346
|
continue
|
|
301
347
|
|
|
302
|
-
if parameters.get(
|
|
348
|
+
if parameters.get("ApSupportsImg4", False) and ("RestoreRequestRules" not in info_dict):
|
|
303
349
|
logger.debug(f'Skipping "{key}" as it doesn\'t have RestoreRequestRules')
|
|
304
350
|
continue
|
|
305
351
|
|
|
306
|
-
if parameters.get(
|
|
307
|
-
if not manifest_node.get(
|
|
308
|
-
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")
|
|
309
355
|
continue
|
|
310
|
-
info = manifest_entry[
|
|
356
|
+
info = manifest_entry["Info"]
|
|
311
357
|
if not is_fw_payload(info):
|
|
312
|
-
logger.debug(f
|
|
358
|
+
logger.debug(f"skipping {key} as it is not a firmware payload")
|
|
313
359
|
continue
|
|
314
360
|
|
|
315
|
-
if info_dict.get(
|
|
316
|
-
logger.debug(
|
|
361
|
+
if info_dict.get("IsFTAB"):
|
|
362
|
+
logger.debug("Skipping IsFTAB")
|
|
317
363
|
continue
|
|
318
364
|
|
|
319
365
|
# copy this entry
|
|
320
366
|
tss_entry = dict(manifest_entry)
|
|
321
367
|
|
|
322
368
|
# remove obsolete Info node
|
|
323
|
-
tss_entry.pop(
|
|
369
|
+
tss_entry.pop("Info")
|
|
324
370
|
|
|
325
371
|
# handle RestoreRequestRules
|
|
326
|
-
if
|
|
327
|
-
rules = manifest_entry[
|
|
372
|
+
if "Info" in manifest_entry and "RestoreRequestRules" in manifest_entry["Info"]:
|
|
373
|
+
rules = manifest_entry["Info"]["RestoreRequestRules"]
|
|
328
374
|
if rules:
|
|
329
|
-
logger.debug(f
|
|
375
|
+
logger.debug(f"Applying restore request rules for entry {key}")
|
|
330
376
|
tss_entry = self.apply_restore_request_rules(tss_entry, parameters, rules)
|
|
331
377
|
|
|
332
378
|
# Make sure we have a Digest key for Trusted items even if empty
|
|
333
|
-
node = manifest_entry.get(
|
|
334
|
-
if node:
|
|
335
|
-
|
|
336
|
-
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""
|
|
337
382
|
|
|
338
383
|
self._request[key] = tss_entry
|
|
339
384
|
|
|
@@ -341,91 +386,115 @@ class TSSRequest:
|
|
|
341
386
|
self._request.update(overrides)
|
|
342
387
|
|
|
343
388
|
def add_ap_img3_tags(self, parameters: dict):
|
|
344
|
-
if
|
|
345
|
-
self._request[
|
|
346
|
-
self._request[
|
|
389
|
+
if "ApNonce" in parameters:
|
|
390
|
+
self._request["ApNonce"] = parameters["ApNonce"]
|
|
391
|
+
self._request["@APTicket"] = True
|
|
347
392
|
|
|
348
393
|
def add_ap_img4_tags(self, parameters):
|
|
349
394
|
keys_to_copy = (
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
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",
|
|
354
413
|
)
|
|
355
414
|
for k in keys_to_copy:
|
|
356
415
|
if k in parameters:
|
|
357
416
|
v = parameters[k]
|
|
358
|
-
if k ==
|
|
359
|
-
k =
|
|
360
|
-
if k ==
|
|
361
|
-
k =
|
|
417
|
+
if k == "ApSepNonce":
|
|
418
|
+
k = "SepNonce"
|
|
419
|
+
if k == "ApSikaFuse":
|
|
420
|
+
k = "Ap,SikaFuse"
|
|
362
421
|
self._request[k] = v
|
|
363
422
|
|
|
364
|
-
uid_mode = parameters.get(
|
|
423
|
+
uid_mode = parameters.get("UID_MODE")
|
|
365
424
|
|
|
366
|
-
if
|
|
367
|
-
self._request[
|
|
425
|
+
if "NeRDEpoch" in parameters:
|
|
426
|
+
self._request["PermitNeRDPivot"] = b""
|
|
368
427
|
|
|
369
428
|
if uid_mode is not None:
|
|
370
|
-
self._request[
|
|
371
|
-
self._request[
|
|
372
|
-
self._request[
|
|
429
|
+
self._request["UID_MODE"] = uid_mode
|
|
430
|
+
self._request["@ApImg4Ticket"] = True
|
|
431
|
+
self._request["@BBTicket"] = True
|
|
373
432
|
|
|
374
|
-
if parameters.get(
|
|
433
|
+
if parameters.get("RequiresUIDMode"):
|
|
375
434
|
# The logic here is missing why this value is expected to be 'false'
|
|
376
|
-
self._request[
|
|
435
|
+
self._request["UID_MODE"] = False
|
|
377
436
|
|
|
378
437
|
# Workaround: We have only seen Ap,SikaFuse together with UID_MODE
|
|
379
|
-
self._request[
|
|
438
|
+
self._request["Ap,SikaFuse"] = 0
|
|
380
439
|
|
|
381
440
|
def add_se_tags(self, parameters: dict, overrides=None):
|
|
382
|
-
manifest = parameters[
|
|
441
|
+
manifest = parameters["Manifest"]
|
|
383
442
|
|
|
384
443
|
# add tags indicating we want to get the SE,Ticket
|
|
385
|
-
self._request[
|
|
386
|
-
self._request[
|
|
444
|
+
self._request["@BBTicket"] = True
|
|
445
|
+
self._request["@SE,Ticket"] = True
|
|
387
446
|
|
|
388
|
-
keys_to_copy = (
|
|
389
|
-
|
|
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
|
+
)
|
|
390
459
|
|
|
391
460
|
for src_key in keys_to_copy:
|
|
392
461
|
if src_key not in parameters:
|
|
393
462
|
continue
|
|
394
463
|
|
|
395
|
-
if src_key.startswith(
|
|
464
|
+
if src_key.startswith("SE"):
|
|
396
465
|
dst_key = src_key
|
|
397
|
-
if not dst_key.startswith(
|
|
466
|
+
if not dst_key.startswith("SE,"):
|
|
398
467
|
# make sure there is a comma (,) after prefix
|
|
399
|
-
dst_key =
|
|
468
|
+
dst_key = "SE," + dst_key.split("SE", 1)[1]
|
|
400
469
|
self._request[dst_key] = parameters[src_key]
|
|
401
470
|
|
|
402
471
|
# 'IsDev' determines whether we have Production or Development
|
|
403
|
-
is_dev = parameters.get(
|
|
472
|
+
is_dev = parameters.get("SE,IsDev")
|
|
404
473
|
if is_dev is None:
|
|
405
|
-
is_dev = parameters.get(
|
|
474
|
+
is_dev = parameters.get("SEIsDev", False)
|
|
406
475
|
|
|
407
476
|
# add SE,* components from build manifest to request
|
|
408
477
|
for key, manifest_entry in manifest.items():
|
|
409
|
-
if not key.startswith(
|
|
478
|
+
if not key.startswith("SE"):
|
|
410
479
|
continue
|
|
411
480
|
|
|
412
481
|
# copy this entry
|
|
413
482
|
tss_entry = dict(manifest_entry)
|
|
414
483
|
|
|
415
484
|
# remove Info node
|
|
416
|
-
tss_entry.pop(
|
|
485
|
+
tss_entry.pop("Info")
|
|
417
486
|
|
|
418
487
|
# remove Development or Production key/hash node
|
|
419
488
|
if is_dev:
|
|
420
|
-
if
|
|
421
|
-
tss_entry.pop(
|
|
422
|
-
if
|
|
423
|
-
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")
|
|
424
493
|
else:
|
|
425
|
-
if
|
|
426
|
-
tss_entry.pop(
|
|
427
|
-
if
|
|
428
|
-
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")
|
|
429
498
|
|
|
430
499
|
# add entry to request
|
|
431
500
|
self._request[key] = tss_entry
|
|
@@ -434,21 +503,27 @@ class TSSRequest:
|
|
|
434
503
|
self._request.update(overrides)
|
|
435
504
|
|
|
436
505
|
def add_savage_tags(self, parameters: dict, overrides=None, component_name=None):
|
|
437
|
-
manifest = parameters[
|
|
506
|
+
manifest = parameters["Manifest"]
|
|
438
507
|
|
|
439
508
|
# add tags indicating we want to get the Savage,Ticket
|
|
440
|
-
self._request[
|
|
441
|
-
self._request[
|
|
509
|
+
self._request["@BBTicket"] = True
|
|
510
|
+
self._request["@Savage,Ticket"] = True
|
|
442
511
|
|
|
443
512
|
# add Savage,UID
|
|
444
|
-
self._request[
|
|
513
|
+
self._request["Savage,UID"] = get_with_or_without_comma(parameters, "Savage,UID")
|
|
445
514
|
|
|
446
515
|
# add SEP
|
|
447
|
-
self._request[
|
|
516
|
+
self._request["SEP"] = {"Digest": manifest["SEP"]["Digest"]}
|
|
448
517
|
|
|
449
518
|
keys_to_copy = (
|
|
450
|
-
|
|
451
|
-
|
|
519
|
+
"Savage,PatchEpoch",
|
|
520
|
+
"Savage,ChipID",
|
|
521
|
+
"Savage,AllowOfflineBoot",
|
|
522
|
+
"Savage,ReadFWKey",
|
|
523
|
+
"Savage,ProductionMode",
|
|
524
|
+
"Savage,Nonce",
|
|
525
|
+
"Savage,Nonce",
|
|
526
|
+
)
|
|
452
527
|
|
|
453
528
|
for k in keys_to_copy:
|
|
454
529
|
value = get_with_or_without_comma(parameters, k)
|
|
@@ -456,22 +531,22 @@ class TSSRequest:
|
|
|
456
531
|
continue
|
|
457
532
|
self._request[k] = value
|
|
458
533
|
|
|
459
|
-
isprod = get_with_or_without_comma(parameters,
|
|
534
|
+
isprod = get_with_or_without_comma(parameters, "Savage,ProductionMode")
|
|
460
535
|
|
|
461
536
|
# get the right component name
|
|
462
|
-
comp_name =
|
|
463
|
-
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")
|
|
464
539
|
|
|
465
540
|
if isinstance(node, bytes):
|
|
466
541
|
savage_rev = node
|
|
467
542
|
if ((savage_rev[0] | 0x10) & 0xF0) == 0x30:
|
|
468
|
-
comp_name =
|
|
543
|
+
comp_name = "Savage,B2-Prod-Patch" if isprod else "Savage,B2-Dev-Patch"
|
|
469
544
|
elif (savage_rev[0] & 0xF0) == 0xA0:
|
|
470
|
-
comp_name =
|
|
545
|
+
comp_name = "Savage,BA-Prod-Patch" if isprod else "Savage,BA-Dev-Patch"
|
|
471
546
|
|
|
472
547
|
# add Savage,B?-*-Patch
|
|
473
548
|
d = dict(manifest[comp_name])
|
|
474
|
-
d.pop(
|
|
549
|
+
d.pop("Info")
|
|
475
550
|
self._request[comp_name] = d
|
|
476
551
|
|
|
477
552
|
if overrides is not None:
|
|
@@ -480,36 +555,44 @@ class TSSRequest:
|
|
|
480
555
|
return comp_name
|
|
481
556
|
|
|
482
557
|
def add_yonkers_tags(self, parameters: dict, overrides=None):
|
|
483
|
-
manifest = parameters[
|
|
558
|
+
manifest = parameters["Manifest"]
|
|
484
559
|
|
|
485
560
|
# add tags indicating we want to get the Yonkers,Ticket
|
|
486
|
-
self._request[
|
|
487
|
-
self._request[
|
|
561
|
+
self._request["@BBTicket"] = True
|
|
562
|
+
self._request["@Yonkers,Ticket"] = True
|
|
488
563
|
|
|
489
564
|
# add SEP
|
|
490
|
-
self._request[
|
|
565
|
+
self._request["SEP"] = {"Digest": manifest["SEP"]["Digest"]}
|
|
491
566
|
|
|
492
567
|
keys_to_copy = (
|
|
493
|
-
|
|
494
|
-
|
|
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
|
+
)
|
|
495
578
|
|
|
496
579
|
for k in keys_to_copy:
|
|
497
580
|
self._request[k] = get_with_or_without_comma(parameters, k)
|
|
498
581
|
|
|
499
|
-
isprod = get_with_or_without_comma(parameters,
|
|
500
|
-
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)
|
|
501
584
|
comp_node = None
|
|
502
585
|
result_comp_name = None
|
|
503
586
|
|
|
504
587
|
for comp_name, node in manifest.items():
|
|
505
|
-
if not comp_name.startswith(
|
|
588
|
+
if not comp_name.startswith("Yonkers,"):
|
|
506
589
|
continue
|
|
507
590
|
|
|
508
591
|
target_node = 1
|
|
509
|
-
sub_node = node.get(
|
|
592
|
+
sub_node = node.get("EPRO")
|
|
510
593
|
if sub_node:
|
|
511
594
|
target_node &= sub_node if isprod else not sub_node
|
|
512
|
-
sub_node = node.get(
|
|
595
|
+
sub_node = node.get("FabRevision")
|
|
513
596
|
if sub_node:
|
|
514
597
|
target_node &= sub_node == fabrevision
|
|
515
598
|
|
|
@@ -519,11 +602,11 @@ class TSSRequest:
|
|
|
519
602
|
break
|
|
520
603
|
|
|
521
604
|
if comp_node is None:
|
|
522
|
-
raise PyMobileDevice3Exception(f
|
|
605
|
+
raise PyMobileDevice3Exception(f"No Yonkers node for {isprod}/{fabrevision}")
|
|
523
606
|
|
|
524
607
|
# add Yonkers,SysTopPatch
|
|
525
608
|
comp_dict = dict(comp_node)
|
|
526
|
-
comp_dict.pop(
|
|
609
|
+
comp_dict.pop("Info")
|
|
527
610
|
self._request[result_comp_name] = comp_dict
|
|
528
611
|
|
|
529
612
|
if overrides is not None:
|
|
@@ -532,45 +615,60 @@ class TSSRequest:
|
|
|
532
615
|
return result_comp_name
|
|
533
616
|
|
|
534
617
|
def add_baseband_tags(self, parameters: dict, overrides=None):
|
|
535
|
-
self._request[
|
|
618
|
+
self._request["@BBTicket"] = True
|
|
536
619
|
|
|
537
620
|
keys_to_copy = (
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
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
|
+
)
|
|
541
634
|
|
|
542
635
|
for k in keys_to_copy:
|
|
543
636
|
if k in parameters:
|
|
544
637
|
self._request[k] = parameters[k]
|
|
545
638
|
|
|
546
|
-
bb_chip_id = parameters[
|
|
547
|
-
bb_cert_id = parameters[
|
|
639
|
+
bb_chip_id = parameters["BbChipID"]
|
|
640
|
+
bb_cert_id = parameters["BbGoldCertId"]
|
|
548
641
|
|
|
549
|
-
bbfwdict = dict(parameters[
|
|
550
|
-
bbfwdict.pop(
|
|
642
|
+
bbfwdict = dict(parameters["Manifest"]["BasebandFirmware"])
|
|
643
|
+
bbfwdict.pop("Info")
|
|
551
644
|
|
|
552
645
|
if bb_chip_id == 0x68:
|
|
553
646
|
# depending on the BasebandCertId remove certain nodes
|
|
554
647
|
if bb_cert_id in (0x26F3FACC, 0x5CF2EC4E, 0x8399785A):
|
|
555
|
-
bbfwdict.pop(
|
|
556
|
-
bbfwdict.pop(
|
|
648
|
+
bbfwdict.pop("PSI2-PartialDigest")
|
|
649
|
+
bbfwdict.pop("RestorePSI2-PartialDigest")
|
|
557
650
|
else:
|
|
558
|
-
bbfwdict.pop(
|
|
559
|
-
bbfwdict.pop(
|
|
651
|
+
bbfwdict.pop("PSI-PartialDigest")
|
|
652
|
+
bbfwdict.pop("RestorePSI-PartialDigest")
|
|
560
653
|
|
|
561
|
-
self._request[
|
|
654
|
+
self._request["BasebandFirmware"] = bbfwdict
|
|
562
655
|
|
|
563
656
|
if overrides:
|
|
564
657
|
self._request.update(overrides)
|
|
565
658
|
|
|
566
659
|
def add_rose_tags(self, parameters: dict, overrides: typing.Optional[dict] = None):
|
|
567
|
-
manifest = parameters[
|
|
660
|
+
manifest = parameters["Manifest"]
|
|
568
661
|
|
|
569
662
|
# add tags indicating we want to get the Rap,Ticket
|
|
570
|
-
self._request[
|
|
571
|
-
self._request[
|
|
572
|
-
|
|
573
|
-
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
|
+
)
|
|
574
672
|
|
|
575
673
|
for key in keys_to_copy_uint:
|
|
576
674
|
value = get_with_or_without_comma(parameters, key)
|
|
@@ -580,41 +678,44 @@ class TSSRequest:
|
|
|
580
678
|
else:
|
|
581
679
|
self._request[key] = value
|
|
582
680
|
|
|
583
|
-
keys_to_copy_bool = (
|
|
681
|
+
keys_to_copy_bool = (
|
|
682
|
+
"Rap,ProductionMode",
|
|
683
|
+
"Rap,SecurityMode",
|
|
684
|
+
)
|
|
584
685
|
|
|
585
686
|
for key in keys_to_copy_bool:
|
|
586
687
|
value = get_with_or_without_comma(parameters, key)
|
|
587
688
|
self._request[key] = bytes_to_uint(value) == 1
|
|
588
689
|
|
|
589
|
-
nonce = get_with_or_without_comma(parameters,
|
|
690
|
+
nonce = get_with_or_without_comma(parameters, "Rap,Nonce")
|
|
590
691
|
if nonce is not None:
|
|
591
|
-
self._request[
|
|
692
|
+
self._request["Rap,Nonce"] = nonce
|
|
592
693
|
|
|
593
|
-
digest = get_with_or_without_comma(parameters,
|
|
694
|
+
digest = get_with_or_without_comma(parameters, "Rap,FdrRootCaDigest")
|
|
594
695
|
if digest is not None:
|
|
595
|
-
self._request[
|
|
696
|
+
self._request["Rap,FdrRootCaDigest"] = digest
|
|
596
697
|
|
|
597
698
|
for comp_name, node in manifest.items():
|
|
598
|
-
if not comp_name.startswith(
|
|
699
|
+
if not comp_name.startswith("Rap,"):
|
|
599
700
|
continue
|
|
600
701
|
|
|
601
702
|
manifest_entry = dict(node)
|
|
602
703
|
|
|
603
704
|
# handle RestoreRequestRules
|
|
604
|
-
rules = manifest_entry[
|
|
705
|
+
rules = manifest_entry["Info"].get("RestoreRequestRules")
|
|
605
706
|
if rules is not None:
|
|
606
707
|
self.apply_restore_request_rules(manifest_entry, parameters, rules)
|
|
607
708
|
|
|
608
709
|
# Make sure we have a Digest key for Trusted items even if empty
|
|
609
|
-
trusted = manifest_entry.get(
|
|
710
|
+
trusted = manifest_entry.get("Trusted", False)
|
|
610
711
|
|
|
611
712
|
if trusted:
|
|
612
|
-
digest = manifest_entry.get(
|
|
713
|
+
digest = manifest_entry.get("Digest")
|
|
613
714
|
if digest is None:
|
|
614
|
-
logger.debug(f
|
|
615
|
-
manifest_entry[
|
|
715
|
+
logger.debug(f"No Digest data, using empty value for entry {comp_name}")
|
|
716
|
+
manifest_entry["Digest"] = b""
|
|
616
717
|
|
|
617
|
-
manifest_entry.pop(
|
|
718
|
+
manifest_entry.pop("Info")
|
|
618
719
|
|
|
619
720
|
# finally add entry to request
|
|
620
721
|
self._request[comp_name] = manifest_entry
|
|
@@ -623,41 +724,41 @@ class TSSRequest:
|
|
|
623
724
|
self._request.update(overrides)
|
|
624
725
|
|
|
625
726
|
def add_veridian_tags(self, parameters: dict, overrides: typing.Optional[dict] = None):
|
|
626
|
-
manifest = parameters[
|
|
727
|
+
manifest = parameters["Manifest"]
|
|
627
728
|
|
|
628
729
|
# add tags indicating we want to get the Rap,Ticket
|
|
629
|
-
self._request[
|
|
630
|
-
self._request[
|
|
730
|
+
self._request["@BBTicket"] = True
|
|
731
|
+
self._request["@BMU,Ticket"] = True
|
|
631
732
|
|
|
632
|
-
self._request[
|
|
633
|
-
self._request[
|
|
634
|
-
self._request[
|
|
733
|
+
self._request["BMU,ChipID"] = parameters["ChipID"]
|
|
734
|
+
self._request["BMU,UniqueID"] = parameters["UniqueID"]
|
|
735
|
+
self._request["BMU,ProductionMode"] = parameters["ProductionMode"]
|
|
635
736
|
|
|
636
|
-
nonce = parameters.get(
|
|
737
|
+
nonce = parameters.get("Nonce")
|
|
637
738
|
if nonce is not None:
|
|
638
|
-
self._request[
|
|
739
|
+
self._request["BMU,Nonce"] = nonce
|
|
639
740
|
|
|
640
741
|
for comp_name, node in manifest.items():
|
|
641
|
-
if not comp_name.startswith(
|
|
742
|
+
if not comp_name.startswith("BMU,"):
|
|
642
743
|
continue
|
|
643
744
|
|
|
644
745
|
manifest_entry = dict(node)
|
|
645
746
|
|
|
646
747
|
# handle RestoreRequestRules
|
|
647
|
-
rules = manifest_entry[
|
|
748
|
+
rules = manifest_entry["Info"].get("RestoreRequestRules")
|
|
648
749
|
if rules is not None:
|
|
649
750
|
self.apply_restore_request_rules(manifest_entry, parameters, rules)
|
|
650
751
|
|
|
651
752
|
# Make sure we have a Digest key for Trusted items even if empty
|
|
652
|
-
trusted = manifest_entry.get(
|
|
753
|
+
trusted = manifest_entry.get("Trusted", False)
|
|
653
754
|
|
|
654
755
|
if trusted:
|
|
655
|
-
digest = manifest_entry.get(
|
|
756
|
+
digest = manifest_entry.get("Digest")
|
|
656
757
|
if digest is None:
|
|
657
|
-
logger.debug(f
|
|
658
|
-
manifest_entry[
|
|
758
|
+
logger.debug(f"No Digest data, using empty value for entry {comp_name}")
|
|
759
|
+
manifest_entry["Digest"] = b""
|
|
659
760
|
|
|
660
|
-
manifest_entry.pop(
|
|
761
|
+
manifest_entry.pop("Info")
|
|
661
762
|
|
|
662
763
|
# finally add entry to request
|
|
663
764
|
self._request[comp_name] = manifest_entry
|
|
@@ -666,14 +767,19 @@ class TSSRequest:
|
|
|
666
767
|
self._request.update(overrides)
|
|
667
768
|
|
|
668
769
|
def add_tcon_tags(self, parameters: dict, overrides: typing.Optional[dict] = None):
|
|
669
|
-
manifest = parameters[
|
|
770
|
+
manifest = parameters["Manifest"]
|
|
670
771
|
|
|
671
772
|
# add tags indicating we want to get the Baobab,Ticket
|
|
672
|
-
self._request[
|
|
673
|
-
self._request[
|
|
674
|
-
|
|
675
|
-
keys_to_copy_uint = (
|
|
676
|
-
|
|
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
|
+
)
|
|
677
783
|
|
|
678
784
|
for key in keys_to_copy_uint:
|
|
679
785
|
value = get_with_or_without_comma(parameters, key)
|
|
@@ -683,26 +789,26 @@ class TSSRequest:
|
|
|
683
789
|
else:
|
|
684
790
|
self._request[key] = value
|
|
685
791
|
|
|
686
|
-
isprod = bool(get_with_or_without_comma(parameters,
|
|
687
|
-
self._request[
|
|
792
|
+
isprod = bool(get_with_or_without_comma(parameters, "Baobab,ProductionMode", False))
|
|
793
|
+
self._request["Baobab,ProductionMode"] = isprod
|
|
688
794
|
|
|
689
|
-
nonce = get_with_or_without_comma(parameters,
|
|
795
|
+
nonce = get_with_or_without_comma(parameters, "Baobab,UpdateNonce")
|
|
690
796
|
|
|
691
797
|
if nonce is not None:
|
|
692
|
-
self._request[
|
|
798
|
+
self._request["Baobab,UpdateNonce"] = nonce
|
|
693
799
|
|
|
694
|
-
ecid = get_with_or_without_comma(parameters,
|
|
800
|
+
ecid = get_with_or_without_comma(parameters, "Baobab,ECID")
|
|
695
801
|
|
|
696
802
|
if ecid is not None:
|
|
697
|
-
self._request[
|
|
803
|
+
self._request["Baobab,ECID"] = ecid
|
|
698
804
|
|
|
699
805
|
for comp_name, node in manifest.items():
|
|
700
|
-
if not comp_name.startswith(
|
|
806
|
+
if not comp_name.startswith("Baobab,"):
|
|
701
807
|
continue
|
|
702
808
|
|
|
703
809
|
manifest_entry = dict(node)
|
|
704
|
-
manifest_entry.pop(
|
|
705
|
-
manifest_entry[
|
|
810
|
+
manifest_entry.pop("Info")
|
|
811
|
+
manifest_entry["EPRO"] = isprod
|
|
706
812
|
|
|
707
813
|
# finally add entry to request
|
|
708
814
|
self._request[comp_name] = manifest_entry
|
|
@@ -713,31 +819,31 @@ class TSSRequest:
|
|
|
713
819
|
def img4_create_local_manifest(self, build_identity=None):
|
|
714
820
|
manifest = None
|
|
715
821
|
if build_identity is not None:
|
|
716
|
-
manifest = build_identity[
|
|
822
|
+
manifest = build_identity["Manifest"]
|
|
717
823
|
|
|
718
824
|
p = asn1.Encoder()
|
|
719
825
|
p.start()
|
|
720
826
|
|
|
721
|
-
p.write(b
|
|
827
|
+
p.write(b"MANP", asn1.Numbers.IA5String)
|
|
722
828
|
p.enter(asn1.Numbers.Set)
|
|
723
829
|
|
|
724
|
-
p.write(b
|
|
725
|
-
p.write(self._request[
|
|
830
|
+
p.write(b"BORD", asn1.Numbers.IA5String)
|
|
831
|
+
p.write(self._request["ApBoardID"], asn1.Numbers.Integer)
|
|
726
832
|
|
|
727
|
-
p.write(b
|
|
833
|
+
p.write(b"CEPO", asn1.Numbers.IA5String)
|
|
728
834
|
p.write(0, asn1.Numbers.Integer)
|
|
729
835
|
|
|
730
|
-
p.write(b
|
|
731
|
-
p.write(self._request[
|
|
836
|
+
p.write(b"CHIP", asn1.Numbers.IA5String)
|
|
837
|
+
p.write(self._request["ApChipID"], asn1.Numbers.Integer)
|
|
732
838
|
|
|
733
|
-
p.write(b
|
|
734
|
-
p.write(self._request[
|
|
839
|
+
p.write(b"CPRO", asn1.Numbers.IA5String)
|
|
840
|
+
p.write(self._request["ApProductionMode"], asn1.Numbers.Integer)
|
|
735
841
|
|
|
736
|
-
p.write(b
|
|
842
|
+
p.write(b"CSEC", asn1.Numbers.IA5String)
|
|
737
843
|
p.write(0, asn1.Numbers.Integer)
|
|
738
844
|
|
|
739
|
-
p.write(b
|
|
740
|
-
p.write(self._request[
|
|
845
|
+
p.write(b"SDOM", asn1.Numbers.IA5String)
|
|
846
|
+
p.write(self._request["ApSecurityDomain"], asn1.Numbers.Integer)
|
|
741
847
|
|
|
742
848
|
p.leave()
|
|
743
849
|
|
|
@@ -747,23 +853,23 @@ class TSSRequest:
|
|
|
747
853
|
# check if component has Img4PayloadType
|
|
748
854
|
comp = None
|
|
749
855
|
if manifest is not None:
|
|
750
|
-
comp = manifest[k][
|
|
856
|
+
comp = manifest[k]["Info"].get("Img4PayloadType")
|
|
751
857
|
|
|
752
858
|
if comp is None:
|
|
753
859
|
comp = COMPONENT_FOURCC.get(k)
|
|
754
860
|
|
|
755
861
|
if comp is None:
|
|
756
|
-
raise NotImplementedError(f
|
|
862
|
+
raise NotImplementedError(f"Unhandled component {k} - can't create manifest")
|
|
757
863
|
|
|
758
|
-
logger.debug(f
|
|
864
|
+
logger.debug(f"found component {comp} ({k})")
|
|
759
865
|
|
|
760
866
|
# write manifest body header
|
|
761
|
-
p.write(b
|
|
867
|
+
p.write(b"MANB", asn1.Numbers.IA5String)
|
|
762
868
|
p.enter(asn1.Numbers.Set)
|
|
763
869
|
p.leave()
|
|
764
870
|
|
|
765
871
|
# write header values
|
|
766
|
-
p.write(b
|
|
872
|
+
p.write(b"IM4M", asn1.Numbers.IA5String)
|
|
767
873
|
p.write(0, asn1.Numbers.Integer)
|
|
768
874
|
|
|
769
875
|
return p.output()
|
|
@@ -777,28 +883,30 @@ class TSSRequest:
|
|
|
777
883
|
|
|
778
884
|
async def send_receive(self) -> TSSResponse:
|
|
779
885
|
headers = {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
886
|
+
"Cache-Control": "no-cache",
|
|
887
|
+
"Content-type": 'text/xml; charset="utf-8"',
|
|
888
|
+
"User-Agent": "InetURL/1.0",
|
|
889
|
+
"Expect": "",
|
|
784
890
|
}
|
|
785
891
|
|
|
786
|
-
logger.info(
|
|
892
|
+
logger.info("Sending TSS request...")
|
|
787
893
|
logger.debug(self._request)
|
|
788
894
|
|
|
789
895
|
loop = asyncio.get_event_loop()
|
|
790
896
|
with ThreadPoolExecutor() as executor:
|
|
897
|
+
|
|
791
898
|
def post() -> bytes:
|
|
792
|
-
return requests.post(
|
|
793
|
-
|
|
899
|
+
return requests.post(
|
|
900
|
+
TSS_CONTROLLER_ACTION_URL, headers=headers, data=plistlib.dumps(self._request), verify=False
|
|
901
|
+
).content
|
|
794
902
|
|
|
795
903
|
content = await loop.run_in_executor(executor, post)
|
|
796
904
|
|
|
797
|
-
if b
|
|
798
|
-
logger.info(
|
|
905
|
+
if b"MESSAGE=SUCCESS" in content:
|
|
906
|
+
logger.info("response successfully received")
|
|
799
907
|
|
|
800
|
-
message = content.split(b
|
|
801
|
-
if message !=
|
|
802
|
-
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}")
|
|
803
911
|
|
|
804
|
-
return TSSResponse(plistlib.loads(content.split(b
|
|
912
|
+
return TSSResponse(plistlib.loads(content.split(b"REQUEST_STRING=", 1)[1]))
|