From 7eaa1fa8546bfa12d23ba30f81db54ae2ff64784 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 6 Apr 2022 14:21:53 +0200 Subject: Add support for Timer,* components and TSS found in iPad Air 5th gen firmware --- src/restore.c | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tss.c | 148 ++++++++++++++++++++++++++++++++++++++++++ src/tss.h | 1 + 3 files changed, 353 insertions(+) diff --git a/src/restore.c b/src/restore.c index ef907ba..48eca78 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2683,6 +2683,204 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct return response; } +static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +{ + char comp_name[64]; + char *comp_path = NULL; + plist_t comp_node = NULL; + unsigned char* component_data = NULL; + unsigned int component_size = 0; + ftab_t ftab = NULL; + ftab_t rftab = NULL; + uint32_t ftag = 0; + plist_t parameters = NULL; + plist_t request = NULL; + plist_t response = NULL; + plist_t node = NULL; + const char* ticket_name = NULL; + uint32_t tag = 0; + int ret; + + /* create Timer request */ + request = tss_request_new(NULL); + if (request == NULL) { + error("ERROR: Unable to create Timer TSS request\n"); + return NULL; + } + + parameters = plist_new_dict(); + + /* add manifest for current build_identity to parameters */ + tss_parameters_add_from_manifest(parameters, build_identity); + + plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); + if (client->image4supported) { + plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); + plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(1)); + } else { + plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0)); + } + + /* add Timer,* tags from info dictionary to parameters */ + plist_t info_array = plist_dict_get_item(p_info, "InfoArray"); + if (!info_array) { + error("ERROR: Could not find InfoArray in info dictionary\n"); + plist_free(parameters); + return NULL; + } else { + plist_t info_dict = plist_array_get_item(info_array, 0); + plist_t hwid = plist_dict_get_item(info_dict, "HardwareID"); + uint64_t u64val; + uint8_t bval; + tag = (uint32_t)_plist_dict_get_uint(info_dict, "TagNumber"); + char key[64]; + + plist_dict_set_item(parameters, "TagNumber", plist_new_uint(tag)); + plist_t node = plist_dict_get_item(info_dict, "TicketName"); + if (node) { + ticket_name = plist_get_string_ptr(node, NULL); + plist_dict_set_item(parameters, "TicketName", plist_copy(node)); + } + + sprintf(key, "Timer,ChipID,%u", tag); + u64val = _plist_dict_get_uint(hwid, "ChipID"); + plist_dict_set_item(parameters, key, plist_new_uint(u64val)); + + sprintf(key, "Timer,BoardID,%u", tag); + u64val = _plist_dict_get_uint(hwid, "BoardID"); + plist_dict_set_item(parameters, key, plist_new_uint(u64val)); + + sprintf(key, "Timer,ECID,%u", tag); + u64val = _plist_dict_get_uint(hwid, "ECID"); + plist_dict_set_item(parameters, key, plist_new_uint(u64val)); + + plist_t p_nonce = plist_dict_get_item(hwid, "Nonce"); + if (p_nonce) { + sprintf(key, "Timer,Nonce,%u", tag); + plist_dict_set_item(parameters, key, plist_copy(p_nonce)); + } + + sprintf(key, "Timer,SecurityMode,%u", tag); + bval = _plist_dict_get_bool(hwid, "SecurityMode"); + plist_dict_set_item(parameters, key, plist_new_bool(bval)); + + sprintf(key, "Timer,SecurityDomain,%u", tag); + u64val = _plist_dict_get_uint(hwid, "SecurityDomain"); + plist_dict_set_item(parameters, key, plist_new_uint(u64val)); + + sprintf(key, "Timer,ProductionMode,%u", tag); + u64val = _plist_dict_get_uint(hwid, "ProductionStatus"); + plist_dict_set_item(parameters, key, plist_new_uint(u64val)); + } + plist_t ap_info = plist_dict_get_item(p_info, "APInfo"); + if (!ap_info) { + error("ERROR: Could not find APInfo in info dictionary\n"); + plist_free(parameters); + return NULL; + } else { + plist_dict_merge(parameters, ap_info); + } + + /* add required tags for Timer TSS request */ + tss_request_add_timer_tags(request, parameters, NULL); + + plist_free(parameters); + + info("Sending %s TSS request...\n", ticket_name); + response = tss_request_send(request, client->tss_url); + plist_free(request); + if (response == NULL) { + error("ERROR: Unable to fetch %s\n", ticket_name); + return NULL; + } + + if (plist_dict_get_item(response, ticket_name)) { + info("Received %s\n", ticket_name); + } else { + error("ERROR: No '%s' in TSS response, this might not work\n", ticket_name); + } + + sprintf(comp_name, "Timer,RTKitOS,%u", tag); + if (build_identity_has_component(build_identity, comp_name)) { + if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + error("ERROR: Unable to 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; + } + if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) { + free(component_data); + error("ERROR: Failed to parse '%s' component data.\n", comp_name); + return NULL; + } + free(component_data); + component_data = NULL; + component_size = 0; + if (ftag != 'rkos') { + error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); + } + } else { + info("NOTE: Build identity does not have a '%s' component.\n", comp_name); + } + + sprintf(comp_name, "Timer,RestoreRTKitOS,%u", tag); + if (build_identity_has_component(build_identity, comp_name)) { + if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + ftab_free(ftab); + error("ERROR: Unable to 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) { + ftab_free(ftab); + error("ERROR: Unable to extract '%s' component\n", comp_name); + return NULL; + } + + ftag = 0; + if (ftab_parse(component_data, component_size, &rftab, &ftag) != 0) { + free(component_data); + ftab_free(ftab); + error("ERROR: Failed to parse '%s' component data.\n", comp_name); + return NULL; + } + free(component_data); + component_data = NULL; + component_size = 0; + if (ftag != 'rkos') { + error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos'); + } + + if (ftab_get_entry_ptr(rftab, 'rrko', &component_data, &component_size) == 0) { + ftab_add_entry(ftab, 'rrko', component_data, component_size); + } else { + error("ERROR: Could not find 'rrko' entry in ftab. This will probably break things.\n"); + } + ftab_free(rftab); + component_data = NULL; + component_size = 0; + } else { + info("NOTE: Build identity does not have a '%s' component.\n", comp_name); + } + + ftab_write(ftab, &component_data, &component_size); + ftab_free(ftab); + + 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; +} + static 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; @@ -2776,6 +2974,12 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct error("ERROR: %s: Couldn't get AppleTCON firmware data\n", __func__); goto error_out; } + } else if (strcmp(s_updater_name, "AppleTypeCRetimer") == 0) { + fwdict = restore_get_timer_firmware_data(restore, client, build_identity, p_info); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); + goto error_out; + } } else { error("ERROR: %s: Got unknown updater name '%s'.\n", __func__, s_updater_name); goto error_out; diff --git a/src/tss.c b/src/tss.c index 084ad10..9c3ad05 100644 --- a/src/tss.c +++ b/src/tss.c @@ -490,6 +490,48 @@ int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity) } node = NULL; + /* add Timer,BoardID,1 */ + node = plist_dict_get_item(build_identity, "Timer,BoardID,1"); + if (node) { + plist_dict_set_item(parameters, "Timer,BoardID,1", plist_copy(node)); + } + node = NULL; + + /* add Timer,BoardID,2 */ + node = plist_dict_get_item(build_identity, "Timer,BoardID,2"); + if (node) { + plist_dict_set_item(parameters, "Timer,BoardID,2", plist_copy(node)); + } + node = NULL; + + /* add Timer,ChipID,1 */ + node = plist_dict_get_item(build_identity, "Timer,ChipID,1"); + if (node) { + plist_dict_set_item(parameters, "Timer,ChipID,1", plist_copy(node)); + } + node = NULL; + + /* add Timer,ChipID,2 */ + node = plist_dict_get_item(build_identity, "Timer,ChipID,2"); + if (node) { + plist_dict_set_item(parameters, "Timer,ChipID,2", plist_copy(node)); + } + node = NULL; + + /* add Timer,SecurityDomain,1 */ + node = plist_dict_get_item(build_identity, "Timer,SecurityDomain,1"); + if (node) { + plist_dict_set_item(parameters, "Timer,SecurityDomain,1", plist_copy(node)); + } + node = NULL; + + /* add Timer,SecurityDomain,2 */ + node = plist_dict_get_item(build_identity, "Timer,SecurityDomain,2"); + if (node) { + plist_dict_set_item(parameters, "Timer,SecurityDomain,2", 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) { @@ -1810,6 +1852,112 @@ int tss_request_add_tcon_tags(plist_t request, plist_t parameters, plist_t overr return 0; } +int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t overrides) +{ + plist_t node = NULL; + uint64_t u64val = 0; + uint8_t bval = 0; + uint32_t tag = 0; + char *ticket_name = 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 Timer ticket */ + plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); + + node = plist_dict_get_item(parameters, "TicketName"); + if (!node) { + error("ERROR: %s: Missing TicketName\n", __func__); + return -1; + } + char key[64]; + sprintf(key, "@%s", plist_get_string_ptr(node, NULL)); + + plist_dict_set_item(request, key, plist_new_bool(1)); + + tag = (uint32_t)_plist_dict_get_uint(parameters, "TagNumber"); + + sprintf(key, "Timer,BoardID,%u", tag); + u64val = _plist_dict_get_uint(parameters, key); + plist_dict_set_item(request, key, plist_new_uint(u64val)); + + sprintf(key, "Timer,ChipID,%u", tag); + u64val = _plist_dict_get_uint(parameters, key); + plist_dict_set_item(request, key, plist_new_uint(u64val)); + + sprintf(key, "Timer,SecurityDomain,%u", tag); + u64val = _plist_dict_get_uint(parameters, key); + plist_dict_set_item(request, key, plist_new_uint(u64val)); + + sprintf(key, "Timer,SecurityMode,%u", tag); + bval = _plist_dict_get_bool(parameters, key); + plist_dict_set_item(request, key, plist_new_bool(bval)); + + sprintf(key, "Timer,ProductionMode,%u", tag); + bval = _plist_dict_get_bool(parameters, key); + plist_dict_set_item(request, key, plist_new_bool(bval)); + + sprintf(key, "Timer,ECID,%u", tag); + u64val = _plist_dict_get_uint(parameters, key); + plist_dict_set_item(request, key, plist_new_uint(u64val)); + + sprintf(key, "Timer,Nonce,%u", tag); + plist_t p_nonce = plist_dict_get_item(parameters, key); + plist_dict_set_item(request, key, plist_copy(p_nonce)); + + char *comp_name = NULL; + plist_dict_iter iter = NULL; + plist_dict_new_iter(manifest_node, &iter); + while (iter) { + node = NULL; + comp_name = NULL; + plist_dict_next_item(manifest_node, iter, &comp_name, &node); + if (comp_name == NULL) { + node = NULL; + break; + } + if (!strncmp(comp_name, "Timer,", 6)) { + plist_t manifest_entry = plist_copy(node); + + /* handle RestoreRequestRules */ + plist_t rules = plist_access_path(manifest_entry, 2, "Info", "RestoreRequestRules"); + if (rules) { + debug("DEBUG: Applying restore request rules for entry %s\n", comp_name); + tss_entry_apply_restore_request_rules(manifest_entry, parameters, rules); + } + + /* Make sure we have a Digest key for Trusted items even if empty */ + plist_t node = plist_dict_get_item(manifest_entry, "Trusted"); + if (node && plist_get_node_type(node) == PLIST_BOOLEAN) { + uint8_t trusted; + plist_get_bool_val(node, &trusted); + if (trusted && !plist_access_path(manifest_entry, 1, "Digest")) { + debug("DEBUG: No Digest data, using empty value for entry %s\n", comp_name); + plist_dict_set_item(manifest_entry, "Digest", plist_new_data(NULL, 0)); + } + } + + plist_dict_remove_item(manifest_entry, "Info"); + + /* finally add entry to request */ + plist_dict_set_item(request, comp_name, manifest_entry); + } + free(comp_name); + } + free(iter); + + /* 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 3590aed..8464f11 100644 --- a/src/tss.h +++ b/src/tss.h @@ -48,6 +48,7 @@ int tss_request_add_vinyl_tags(plist_t request, plist_t parameters, plist_t over int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overrides); int tss_request_add_veridian_tags(plist_t request, plist_t parameters, plist_t overrides); int tss_request_add_tcon_tags(plist_t request, plist_t parameters, plist_t overrides); +int tss_request_add_timer_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