From b023935f5e36fe32ce649dcf0a9a2f7291d281a6 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 6 Nov 2017 15:05:24 +0400 Subject: Add support for Savage firmware updating (found in iPhone X) --- src/restore.c | 108 ++++++++++++++++++++++++++++++++++--- src/tss.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tss.h | 1 + 3 files changed, 269 insertions(+), 7 deletions(-) diff --git a/src/restore.c b/src/restore.c index ab7e50d..85e34f4 100644 --- a/src/restore.c +++ b/src/restore.c @@ -83,6 +83,8 @@ #define UPDATE_SWDHID 56 #define UPDATE_S3E_FIRMWARE 58 #define UPDATE_SE_FIRMWARE 59 +#define UPDATE_SAVAGE 60 +#define CERTIFY_SAVAGE 61 static int restore_finished = 0; @@ -552,6 +554,10 @@ const char* restore_progress_string(unsigned int operation) return "Updating S3E Firmware"; case UPDATE_SE_FIRMWARE: return "Updating SE Firmware"; + case UPDATE_SAVAGE: + return "Updating Savage"; + case CERTIFY_SAVAGE: + return "Certifying Savage"; default: return "Unknown operation"; } @@ -1853,6 +1859,88 @@ plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicere return response; } +plist_t restore_get_savage_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +{ + const char *comp_name = NULL; + char *comp_path = NULL; + unsigned char* component_data = NULL; + unsigned int component_size = 0; + plist_t fwdict = NULL; + plist_t parameters = NULL; + plist_t request = NULL; + plist_t response = NULL; + plist_t node = NULL; + uint8_t isprod = 0; + int ret; + + node = plist_dict_get_item(p_info, "Savage,ProductionMode"); + if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) { + plist_get_bool_val(node, &isprod); + } + node = NULL; + if (isprod) { + comp_name = "Savage,B2-Prod-Patch"; + } else { + comp_name = "Savage,B2-Dev-Patch"; + } + + if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + error("ERROR: Unable get path for '%s' component\n", comp_name); + return NULL; + } + + ret = extract_component(client->ipsw, comp_path, &component_data, &component_size); + free(comp_path); + comp_path = NULL; + if (ret < 0) { + error("ERROR: Unable to extract '%s' component\n", comp_name); + return NULL; + } + + /* create Savage request */ + request = tss_request_new(NULL); + if (request == NULL) { + error("ERROR: Unable to create Savage TSS request\n"); + free(component_data); + return NULL; + } + + parameters = plist_new_dict(); + + /* add manifest for current build_identity to parameters */ + tss_parameters_add_from_manifest(parameters, build_identity); + + /* add Savage,* tags from info dictionary to parameters */ + plist_dict_merge(¶meters, p_info); + + /* add required tags for Savage TSS request */ + tss_request_add_savage_tags(request, parameters, NULL); + + plist_free(parameters); + + info("Sending Savage TSS request...\n"); + response = tss_request_send(request, client->tss_url); + plist_free(request); + if (response == NULL) { + error("ERROR: Unable to fetch Savage ticket\n"); + free(component_data); + return NULL; + } + + if (plist_dict_get_item(response, "Savage,Ticket")) { + info("Received Savage ticket\n"); + } else { + error("ERROR: No 'Savage,Ticket' in TSS response, this might not work\n"); + } + + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, (uint64_t) component_size)); + free(component_data); + component_data = NULL; + component_size = 0; + + return response; +} + int restore_send_firmware_updater_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) { plist_t arguments; @@ -1909,19 +1997,25 @@ int restore_send_firmware_updater_data(restored_client_t restore, struct idevice plist_get_string_val(p_updater_name, &s_updater_name); - if (strcmp(s_updater_name, "SE")) { + if (strcmp(s_updater_name, "SE") == 0) { + fwdict = restore_get_se_firmware_data(restore, client, build_identity, p_info); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get SE firmware data\n", __func__); + goto error_out; + } + } else if (strcmp(s_updater_name, "Savage") == 0) { + fwdict = restore_get_savage_firmware_data(restore, client, build_identity, p_info); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get Savage firmware data\n", __func__); + goto error_out; + } + } else { error("ERROR: %s: Got unknown updater name '%s'.", __func__, s_updater_name); goto error_out; } free(s_updater_name); s_updater_name = NULL; - fwdict = restore_get_se_firmware_data(restore, client, build_identity, p_info); - if (fwdict == NULL) { - error("ERROR: %s: Couldn't get SE firmware data\n", __func__); - goto error_out; - } - dict = plist_new_dict(); plist_dict_set_item(dict, "FirmwareResponseData", fwdict); diff --git a/src/tss.c b/src/tss.c index ed45c24..5a6af44 100644 --- a/src/tss.c +++ b/src/tss.c @@ -202,6 +202,51 @@ int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity) } node = NULL; + /* SE,ChipID - Used for SE firmware request */ + node = plist_dict_get_item(build_identity, "SE,ChipID"); + if (node) { + if (plist_get_node_type(node) == PLIST_STRING) { + char *strval = NULL; + int intval = 0; + plist_get_string_val(node, &strval); + sscanf(strval, "%x", &intval); + plist_dict_set_item(parameters, "SE,ChipID", plist_new_uint(intval)); + } else { + plist_dict_set_item(parameters, "SE,ChipID", plist_copy(node)); + } + } + node = NULL; + + /* Savage,ChipID - Used for Savage firmware request */ + node = plist_dict_get_item(build_identity, "Savage,ChipID"); + if (node) { + if (plist_get_node_type(node) == PLIST_STRING) { + char *strval = NULL; + int intval = 0; + plist_get_string_val(node, &strval); + sscanf(strval, "%x", &intval); + plist_dict_set_item(parameters, "Savage,ChipID", plist_new_uint(intval)); + } else { + plist_dict_set_item(parameters, "Savage,ChipID", plist_copy(node)); + } + } + node = NULL; + + /* add Savage,PatchEpoch - Used for Savage firmware request */ + node = plist_dict_get_item(build_identity, "Savage,PatchEpoch"); + if (node) { + if (plist_get_node_type(node) == PLIST_STRING) { + char *strval = NULL; + int intval = 0; + plist_get_string_val(node, &strval); + sscanf(strval, "%x", &intval); + plist_dict_set_item(parameters, "Savage,PatchEpoch", plist_new_uint(intval)); + } else { + plist_dict_set_item(parameters, "Savage,PatchEpoch", plist_copy(node)); + } + } + node = NULL; + /* add build identity manifest dictionary */ node = plist_dict_get_item(build_identity, "Manifest"); if (!node || plist_get_node_type(node) != PLIST_DICT) { @@ -735,6 +780,128 @@ int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrid return 0; } +int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t overrides) +{ + plist_t node = NULL; + + plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); + if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { + error("ERROR: %s: Unable to get restore manifest from parameters\n", __func__); + return -1; + } + + /* add tags indicating we want to get the Savage,Ticket */ + plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); + plist_dict_set_item(request, "@Savage,Ticket", plist_new_bool(1)); + + /* add Savage,UID */ + node = plist_dict_get_item(parameters, "Savage,UID"); + if (!node) { + error("ERROR: %s: Unable to find required Savage,UID in parameters\n", __func__); + return -1; + } + plist_dict_set_item(request, "Savage,UID", plist_copy(node)); + node = NULL; + + /* add SEP */ + node = plist_access_path(manifest_node, 2, "SEP", "Digest"); + if (!node) { + error("ERROR: Unable to get SEP digest from manifest\n"); + return -1; + } + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "Digest", plist_copy(node)); + plist_dict_set_item(request, "SEP", dict); + + /* add Savage,PatchEpoch */ + node = plist_dict_get_item(parameters, "Savage,PatchEpoch"); + if (!node) { + error("ERROR: %s: Unable to find required Savage,PatchEpoch in parameters\n", __func__); + return -1; + } + plist_dict_set_item(request, "Savage,PatchEpoch", plist_copy(node)); + node = NULL; + + /* add Savage,ChipID */ + node = plist_dict_get_item(parameters, "Savage,ChipID"); + if (!node) { + error("ERROR: %s: Unable to find required Savage,ChipID in parameters\n", __func__); + return -1; + } + plist_dict_set_item(request, "Savage,ChipID", plist_copy(node)); + node = NULL; + + /* add Savage,AllowOfflineBoot */ + node = plist_dict_get_item(parameters, "Savage,AllowOfflineBoot"); + if (!node) { + error("ERROR: %s: Unable to find required Savage,AllowOfflineBoot in parameters\n", __func__); + return -1; + } + plist_dict_set_item(request, "Savage,AllowOfflineBoot", plist_copy(node)); + node = NULL; + + /* add Savage,ReadFWKey */ + node = plist_dict_get_item(parameters, "Savage,ReadFWKey"); + if (!node) { + error("ERROR: %s: Unable to find required Savage,ReadFWKey in parameters\n", __func__); + return -1; + } + plist_dict_set_item(request, "Savage,ReadFWKey", plist_copy(node)); + node = NULL; + + /* add Savage,ProductionMode */ + node = plist_dict_get_item(parameters, "Savage,ProductionMode"); + if (!node) { + error("ERROR: %s: Unable to find required Savage,ProductionMode in parameters\n", __func__); + return -1; + } + plist_dict_set_item(request, "Savage,ProductionMode", plist_copy(node)); + const char *comp_name = NULL; + uint8_t isprod = 0; + plist_get_bool_val(node, &isprod); + node = NULL; + + /* add Savage,B2-*-Patch */ + if (isprod) { + comp_name = "Savage,B2-Prod-Patch"; + } else { + comp_name = "Savage,B2-Dev-Patch"; + } + node = plist_access_path(manifest_node, 2, comp_name, "Digest"); + if (!node) { + error("ERROR: Unable to get %s digest from manifest\n", comp_name); + return -1; + } + dict = plist_new_dict(); + plist_dict_set_item(dict, "Digest", plist_copy(node)); + plist_dict_set_item(request, comp_name, dict); + + /* add Savage,Nonce */ + node = plist_dict_get_item(parameters, "Savage,Nonce"); + if (!node) { + error("ERROR: %s: Unable to find required Savage,Nonce in parameters\n", __func__); + return -1; + } + plist_dict_set_item(request, "Savage,Nonce", plist_copy(node)); + node = NULL; + + /* add Savage,ReadECKey */ + node = plist_dict_get_item(parameters, "Savage,ReadECKey"); + if (!node) { + error("ERROR: %s: Unable to find required Savage,ReadECKey in parameters\n", __func__); + return -1; + } + plist_dict_set_item(request, "Savage,ReadECKey", plist_copy(node)); + node = NULL; + + /* apply overrides */ + if (overrides) { + plist_dict_merge(&request, overrides); + } + + return 0; +} + static size_t tss_write_callback(char* data, size_t size, size_t nmemb, tss_response* response) { size_t total = size * nmemb; if (total != 0) { diff --git a/src/tss.h b/src/tss.h index 8eb7083..0c62d26 100644 --- a/src/tss.h +++ b/src/tss.h @@ -40,6 +40,7 @@ int tss_request_add_common_tags(plist_t request, plist_t parameters, plist_t ove int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrides); int tss_request_add_baseband_tags(plist_t request, plist_t parameters, plist_t overrides); int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrides); +int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t overrides); int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters); int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters); -- cgit v1.1-32-gdbae