From 65f170986d03fb536e48967cf3ffc5fb91f57a2d Mon Sep 17 00:00:00 2001 From: Munehisa Kamata Date: Sun, 17 Jul 2022 13:33:33 -0700 Subject: [PATCH 001/117] restore: use an appropriate ticket for Cryptex1 global manifest macOS 13 introduced a new global manifest for Cryptex1 and it requires tickets found in Firmware/Manifests/restore/cryptex1/macOS Customer/ inside an IPSW, but we currently do not use the tickets and end up unexpected behavior on a Mac device after restoring, e.g. bputil fails to downgrade security mode due to "Cryptex1 manifest verification failed". This adds a proper handling to use the appropriate tickets. Signed-off-by: Munehisa Kamata --- src/restore.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/restore.c b/src/restore.c index d51de03c..1a15959b 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3293,7 +3293,7 @@ int extract_macos_variant(plist_t build_identity, char** output) return 0; } -int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, unsigned char** pbuffer, unsigned int* psize) +int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, unsigned char** pbuffer, unsigned int* psize) { plist_t build_info = plist_dict_get_item(build_identity, "Info"); if (!build_info) { @@ -3310,10 +3310,15 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil plist_get_string_val(device_class_node, &device_class); char *macos_variant = NULL; - int ret = extract_macos_variant(build_identity, &macos_variant); - if (ret != 0) { - free(device_class); - return -1; + int ret; + if (variant) { + macos_variant = variant; + } else { + ret = extract_macos_variant(build_identity, &macos_variant); + if (ret != 0) { + free(device_class); + return -1; + } } // The path of the global manifest is hardcoded. There's no pointer to in the build manifest. @@ -3362,7 +3367,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i info("About to send %s...\n", component_name); if (strcmp(image_name, "__GlobalManifest__") == 0) { - int ret = extract_global_manifest(client, build_identity, &data, &size); + int ret = extract_global_manifest(client, build_identity, NULL, &data, &size); if (ret != 0) { return -1; } @@ -3488,7 +3493,19 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice info("About to send %s...\n", component_name); if (strcmp(image_name, "__GlobalManifest__") == 0) { - int ret = extract_global_manifest(client, build_identity, &data, &size); + char *variant = NULL; + plist_t node = plist_access_path(msg, 2, "Arguments", "Variant"); + if (!node || plist_get_node_type(node) != PLIST_STRING) { + debug("Failed to parse arguments from SourceBootObjectV4 plist\n"); + return -1; + } + plist_get_string_val(node, &variant); + if (!variant) { + debug("Failed to parse arguments from SourceBootObjectV4 as string\n"); + return -1; + } + + int ret = extract_global_manifest(client, build_identity, variant, &data, &size); if (ret != 0) { return -1; } From d0921e4b468500874773561a341cd662e3fb73fa Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 29 Aug 2022 03:52:54 +0200 Subject: [PATCH 002/117] restore: Add support for Cryptex1LocalPolicy firmware updater --- src/restore.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/restore.c b/src/restore.c index 1a15959b..30fccbe4 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2860,10 +2860,22 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_t request = NULL; plist_t response = NULL; - /* create Timer request */ + plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName"); + const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL); + + plist_t device_generated_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags"); + const char* response_ticket = "Cryptex1,Ticket"; + if (PLIST_IS_ARRAY(device_generated_tags)) { + plist_t tag0 = plist_array_get_item(device_generated_tags, 0); + if (tag0) { + response_ticket = plist_get_string_ptr(tag0, NULL); + } + } + + /* create Cryptex1 request */ request = tss_request_new(NULL); if (request == NULL) { - error("ERROR: Unable to create Cryptex1 TSS request\n"); + error("ERROR: Unable to create %s TSS request\n", s_updater_name); return NULL; } @@ -2875,7 +2887,7 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); - /* add Timer,* tags from info dictionary to parameters */ + /* add tags from info dictionary to parameters */ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (!device_generated_request) { error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n"); @@ -2894,18 +2906,19 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_free(parameters); - info("Sending Cryptex1 TSS request...\n"); + info("Sending %s TSS request...\n", s_updater_name); response = tss_request_send(request, client->tss_url); plist_free(request); if (response == NULL) { - error("ERROR: Unable to fetch Cryptex1\n"); + error("ERROR: Unable to fetch %s ticket\n", s_updater_name); return NULL; } - if (plist_dict_get_item(response, "Cryptex1,Ticket")) { - info("Received Cryptex1,Ticket\n"); + if (plist_dict_get_item(response, response_ticket)) { + info("Received %s\n", response_ticket); } else { - error("ERROR: No 'Cryptex1,Ticket' in TSS response, this might not work\n"); + error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket); + debug_plist(response); } return response; @@ -3034,10 +3047,10 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); goto error_out; } - } else if (strcmp(s_updater_name, "Cryptex1") == 0) { + } else if ((strcmp(s_updater_name, "Cryptex1") == 0) || (strcmp(s_updater_name, "Cryptex1LocalPolicy") == 0)) { fwdict = restore_get_cryptex1_firmware_data(restore, client, build_identity, p_info, arguments); if (fwdict == NULL) { - error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); + error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else { From d97f560eb1dad839f68a2b8c970ce62432893954 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 16 Sep 2022 15:57:32 +0200 Subject: [PATCH 003/117] Fix Cryptex1 and Cryptex1LocalPolicy TSS request handling --- src/restore.c | 50 +++++++++++++++++++++++++++++++++++--------------- src/tss.c | 38 ++++++++++++++++++++++++++++++++++++++ src/tss.h | 1 + 3 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/restore.c b/src/restore.c index 30fccbe4..17c9b24d 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2863,10 +2863,10 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName"); const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL); - plist_t device_generated_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags"); + plist_t response_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags"); const char* response_ticket = "Cryptex1,Ticket"; - if (PLIST_IS_ARRAY(device_generated_tags)) { - plist_t tag0 = plist_array_get_item(device_generated_tags, 0); + if (PLIST_IS_ARRAY(response_tags)) { + plist_t tag0 = plist_array_get_item(response_tags, 0); if (tag0) { response_ticket = plist_get_string_ptr(tag0, NULL); } @@ -2881,28 +2881,48 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str parameters = plist_new_dict(); - /* add manifest for current build_identity to parameters (Cryptex1 will require the manifest in a seperate message) */ - tss_parameters_add_from_manifest(parameters, build_identity, false); + /* merge data from MessageArgInfo */ + plist_dict_merge(¶meters, p_info); - plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); - plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); + /* add tags from manifest to parameters */ + plist_t build_identity_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "BuildIdentityTags"); + if (PLIST_IS_ARRAY(build_identity_tags)) { + uint32_t i = 0; + for (i = 0; i < plist_array_get_size(build_identity_tags); i++) { + plist_t node = plist_array_get_item(build_identity_tags, i); + const char* key = plist_get_string_ptr(node, NULL); + plist_t item = plist_dict_get_item(build_identity, key); + if (item) { + plist_dict_set_item(parameters, key, plist_copy(item)); + } + } + } - /* add tags from info dictionary to parameters */ + /* make sure we always have these required tags defined */ + if (!plist_dict_get_item(parameters, "ApProductionMode")) { + plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); + } + if (!plist_dict_get_item(parameters, "ApSecurityMode")) { + plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); + } + if (!plist_dict_get_item(parameters, "ApChipID")) { + _plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL); + } + if (!plist_dict_get_item(parameters, "ApBoardID")) { + _plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL); + } + + /* add device generated request data to parameters */ plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); if (!device_generated_request) { error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n"); plist_free(parameters); return NULL; } - plist_dict_merge(¶meters, device_generated_request); - /* add common tags */ - tss_request_add_common_tags(request, p_info, NULL); - - /* add Cryptex1 tags */ - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_merge(&request, parameters); + /* add Cryptex1 tags to request */ + tss_request_add_cryptex_tags(request, parameters, NULL); plist_free(parameters); diff --git a/src/tss.c b/src/tss.c index b6980a73..e916790f 100644 --- a/src/tss.c +++ b/src/tss.c @@ -1381,6 +1381,44 @@ int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t over return 0; } +int tss_request_add_cryptex_tags(plist_t request, plist_t parameters, plist_t overrides) +{ + tss_request_add_common_tags(request, parameters, NULL); + + if (plist_dict_get_item(parameters, "Ap,LocalPolicy")) { + /* Cryptex1LocalPolicy */ + tss_request_add_local_policy_tags(request, parameters); + _plist_dict_copy_data(request, parameters, "Ap,NextStageCryptex1IM4MHash", NULL); + } else { + /* Cryptex1 */ + plist_dict_set_item(request, "@Cryptex1,Ticket", plist_new_bool(1)); + + _plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL); + _plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL); + + plist_dict_iter iter = NULL; + plist_dict_new_iter(parameters, &iter); + plist_t value = NULL; + while (1) { + char *key = NULL; + plist_dict_next_item(parameters, iter, &key, &value); + if (key == NULL) + break; + if (strncmp(key, "Cryptex1", 8) == 0) { + plist_dict_set_item(request, key, plist_copy(value)); + } + free(key); + } + } + + /* 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; diff --git a/src/tss.h b/src/tss.h index 719be818..8af2fcca 100644 --- a/src/tss.h +++ b/src/tss.h @@ -50,6 +50,7 @@ int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overr 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_cryptex_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); From 403d2956bee60c321669421edbde29c97c238928 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 16 Sep 2022 16:00:20 +0200 Subject: [PATCH 004/117] tss: Don't add @BBTicket in tss_request_new() --- src/idevicerestore.c | 2 +- src/tss.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 23c48d5f..641eddb4 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -2269,7 +2269,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie tss_parameters_add_from_manifest(parameters, build_identity, true); /* create basic request */ - /* Adds @BBTicket, @HostPlatformInfo, @VersionInfo, @UUID */ + /* Adds @HostPlatformInfo, @VersionInfo, @UUID */ request = tss_request_new(NULL); if (request == NULL) { error("ERROR: Unable to create TSS request\n"); diff --git a/src/tss.c b/src/tss.c index e916790f..c85758e0 100644 --- a/src/tss.c +++ b/src/tss.c @@ -65,7 +65,6 @@ plist_t tss_request_new(plist_t overrides) { plist_t request = plist_new_dict(); - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@HostPlatformInfo", #ifdef WIN32 plist_new_string("windows") From e9c800732b9a2be95f74b136ad6d2903d3bee56d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 20 Sep 2022 16:30:27 +0200 Subject: [PATCH 005/117] ipsw: Add some NULL checks to ipsw_extract_to_file_with_progress() --- src/ipsw.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/ipsw.c b/src/ipsw.c index 639ecf58..d4ee5e52 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -393,7 +393,14 @@ int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size) int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, const char* outfile, int print_progress) { int ret = 0; - ipsw_archive* archive = ipsw_open(ipsw); + ipsw_archive* archive = NULL; + + if (!ipsw || !infile || !outfile) { + error("ERROR: Invalid argument\n"); + return -1; + } + + archive = ipsw_open(ipsw); if (archive == NULL) { error("ERROR: Invalid archive\n"); return -1; @@ -468,6 +475,10 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con char *filepath = build_path(archive->path, infile); char actual_filepath[PATH_MAX+1]; char actual_outfile[PATH_MAX+1]; + if (!filepath) { + ret = -1; + goto leave; + } if (!realpath(filepath, actual_filepath)) { error("ERROR: realpath failed on %s: %s\n", filepath, strerror(errno)); ret = -1; From 6672bad275ed84a1c14e49cf24613261fe22098b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 21 Sep 2022 09:28:29 +0200 Subject: [PATCH 006/117] tss: Add NeRDEpoch to TSS requests for newer devices (iPhone 13 and up) --- src/tss.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tss.c b/src/tss.c index c85758e0..d8f97891 100644 --- a/src/tss.c +++ b/src/tss.c @@ -216,6 +216,7 @@ int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, _plist_dict_copy_uint(parameters, build_identity, "eUICC,ChipID", NULL); + _plist_dict_copy_uint(parameters, build_identity, "NeRDEpoch", NULL); _plist_dict_copy_data(parameters, build_identity, "PearlCertificationRootPub", NULL); _plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,1", NULL); @@ -289,6 +290,7 @@ int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) } _plist_dict_copy_data(request, parameters, "SepNonce", "ApSepNonce"); + _plist_dict_copy_uint(request, parameters, "NeRDEpoch", NULL); _plist_dict_copy_data(request, parameters, "PearlCertificationRootPub", NULL); return 0; From 96f68e6d8826a696747fb2a403a8e39297fff1b9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 21 Sep 2022 09:55:41 +0200 Subject: [PATCH 007/117] img4: Add some more component tags --- src/img4.c | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/img4.c b/src/img4.c index 609e80be..6cff3497 100644 --- a/src/img4.c +++ b/src/img4.c @@ -275,28 +275,37 @@ static const char *_img4_get_component_tag(const char *compname) { "ACIBT", "acib" }, { "ACIBTLPEM", "lpbt" }, { "ACIWIFI", "aciw" }, - { "Alamo", "almo" }, { "ANE", "anef" }, { "ANS", "ansf" }, { "AOP", "aopf" }, + { "AVE", "avef" }, + { "Alamo", "almo" }, + { "Ap,ANE1", "ane1" }, + { "Ap,ANE2", "ane2" }, + { "Ap,ANE3", "ane3" }, { "Ap,AudioAccessibilityBootChime", "auac" }, { "Ap,AudioBootChime", "aubt" }, { "Ap,AudioPowerAttachChime", "aupr" }, + { "Ap,BootabilityBrainTrustCache", "trbb" }, { "Ap,CIO", "ciof" }, { "Ap,HapticAssets", "hpas" }, { "Ap,LocalBoot", "lobo" }, { "Ap,LocalPolicy", "lpol" }, { "Ap,NextStageIM4MHash", "nsih" }, { "Ap,RecoveryOSPolicyNonceHash", "ronh" }, + { "Ap,RestoreANE1", "ran1" }, + { "Ap,RestoreANE2", "ran2" }, + { "Ap,RestoreANE3", "ran3" }, { "Ap,RestoreCIO", "rcio" }, { "Ap,RestoreTMU", "rtmu" }, { "Ap,Scorpius", "scpf" }, { "Ap,SystemVolumeCanonicalMetadata", "msys" }, { "Ap,TMU", "tmuf" }, { "Ap,VolumeUUID", "vuid" }, + { "Ap,rOSLogo1", "rlg1" }, + { "Ap,rOSLogo2", "rlg2" }, { "AppleLogo", "logo" }, { "AudioCodecFirmware", "acfw" }, - { "AVE", "avef" }, { "BatteryCharging", "glyC" }, { "BatteryCharging0", "chg0" }, { "BatteryCharging1", "chg1" }, @@ -305,28 +314,22 @@ static const char *_img4_get_component_tag(const char *compname) { "BatteryLow1", "bat1" }, { "BatteryPlugin", "glyP" }, { "CFELoader", "cfel" }, - { "Dali", "dali" }, + { "CrownFirmware", "crwn" }, { "DCP", "dcpf" }, + { "Dali", "dali" }, { "DeviceTree", "dtre" }, { "Diags", "diag" }, { "EngineeringTrustCache", "dtrs" }, { "ExtDCP", "edcp" }, - { "ftap", "ftap" }, - { "ftsp", "ftsp" }, { "GFX", "gfxf" }, { "Hamm", "hamf" }, { "Homer", "homr" }, - { "iBEC", "ibec" }, - { "iBoot", "ibot" }, - { "iBootData", "ibdt" }, - { "iBootTest", "itst" }, - { "iBSS", "ibss" }, - { "InputDevice", "ipdf" }, { "ISP", "ispf" }, + { "InputDevice", "ipdf" }, { "KernelCache", "krnl" }, + { "LLB", "illb" }, { "LeapHaptics", "lphp" }, { "Liquid", "liqd" }, - { "LLB", "illb" }, { "LoadableTrustCache", "ltrs" }, { "LowPowerWallet0", "lpw0" }, { "LowPowerWallet1", "lpw1" }, @@ -337,12 +340,13 @@ static const char *_img4_get_component_tag(const char *compname) { "NeedService", "nsrv" }, { "OS", "OS\0\0" }, { "OSRamdisk", "osrd" }, - { "PersonalizedDMG", "pdmg" }, { "PEHammer", "hmmr" }, { "PERTOS", "pert" }, { "PHLEET", "phlt" }, { "PMP", "pmpf" }, + { "PersonalizedDMG", "pdmg" }, { "RBM", "rmbt" }, + { "RTP", "rtpf" }, { "Rap,SoftwareBinaryDsp1", "sbd1" }, { "Rap,RTKitOS", "rkos" }, { "Rap,RestoreRTKitOS", "rrko" }, @@ -353,12 +357,10 @@ static const char *_img4_get_component_tag(const char *compname) { "RestoreExtDCP", "recp" }, { "RestoreKernelCache", "rkrn" }, { "RestoreLogo", "rlgo" }, + { "RestoreRTP", "rrtp" }, { "RestoreRamDisk", "rdsk" }, { "RestoreSEP", "rsep" }, { "RestoreTrustCache", "rtsc" }, - { "rfta", "rfta" }, - { "rfts", "rfts" }, - { "RTP", "rtpf" }, { "SCE", "scef" }, { "SCE1Firmware", "sc1f" }, { "SEP", "sepi" }, @@ -367,6 +369,16 @@ static const char *_img4_get_component_tag(const char *compname) { "SystemLocker", "lckr" }, { "SystemVolume", "isys" }, { "WCHFirmwareUpdater", "wchf" }, + { "ftap", "ftap" }, + { "ftsp", "ftsp" }, + { "iBEC", "ibec" }, + { "iBSS", "ibss" }, + { "iBoot", "ibot" }, + { "iBootData", "ibdt" }, + { "iBootDataStage1", "ibd1" }, + { "iBootTest", "itst" }, + { "rfta", "rfta" }, + { "rfts", "rfts" }, { NULL, NULL } }; int i = 0; From 88aeb4ce1313a9e89209c08efa62fb6b7eb428c4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 25 Sep 2022 11:42:35 +0200 Subject: [PATCH 008/117] tss: Make sure vinyl tags include eUICC,Gold and eUICC,Main digests ... as well as eUICC,ApProductionMode which was missing before. --- src/tss.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/tss.c b/src/tss.c index d8f97891..f162a826 100644 --- a/src/tss.c +++ b/src/tss.c @@ -1075,10 +1075,29 @@ int tss_request_add_vinyl_tags(plist_t request, plist_t parameters, plist_t over plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@eUICC,Ticket", plist_new_bool(1)); + _plist_dict_copy_bool(request, parameters, "eUICC,ApProductionMode", "ApProductionMode"); _plist_dict_copy_uint(request, parameters, "eUICC,ChipID", NULL); _plist_dict_copy_data(request, parameters, "eUICC,EID", NULL); _plist_dict_copy_data(request, parameters, "eUICC,RootKeyIdentifier", NULL); + if (!plist_dict_get_item(request, "eUICC,Gold")) { + plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Gold"); + if (n) { + plist_t p = plist_new_dict(); + _plist_dict_copy_data(p, n, "Digest", NULL); + plist_dict_set_item(request, "eUICC,Gold", p); + } + } + + if (!plist_dict_get_item(request, "eUICC,Main")) { + plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Main"); + if (n) { + plist_t p = plist_new_dict(); + _plist_dict_copy_data(p, n, "Digest", NULL); + plist_dict_set_item(request, "eUICC,Main", p); + } + } + /* set Nonce for eUICC,Gold component */ node = plist_dict_get_item(parameters, "EUICCGoldNonce"); if (node) { From bb7f206090649933ad616baa1b9497ee978052c8 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 25 Sep 2022 13:15:44 +0200 Subject: [PATCH 009/117] tss: Add preliminary code to set UID_MODE --- src/tss.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tss.c b/src/tss.c index f162a826..da4cf178 100644 --- a/src/tss.c +++ b/src/tss.c @@ -245,6 +245,11 @@ int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainVolume", NULL); _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainTrustCache", NULL); + node = plist_dict_get_item(build_identity, "Info"); + if (node) { + _plist_dict_copy_bool(parameters, node, "RequiresUIDMode", NULL); + } + if (include_manifest) { /* add build identity manifest dictionary */ node = plist_dict_get_item(build_identity, "Manifest"); @@ -293,6 +298,13 @@ int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) _plist_dict_copy_uint(request, parameters, "NeRDEpoch", NULL); _plist_dict_copy_data(request, parameters, "PearlCertificationRootPub", NULL); + if (plist_dict_get_item(parameters, "UID_MODE")) { + _plist_dict_copy_item(request, parameters, "UID_MODE", NULL); + } else if (_plist_dict_get_bool(parameters, "RequiresUIDMode")) { + // The logic here is missing why this value is expected to be 'false' + plist_dict_set_item(request, "UID_MODE", plist_new_bool(0)); + } + return 0; } From aa98e764bff59b45173a86d2587b59f5692982eb Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 2 Oct 2022 11:32:19 +0200 Subject: [PATCH 010/117] Reduce memory usage for SourceBootObjectV4 images --- src/idevicerestore.c | 2 +- src/ipsw.c | 141 +++++++++++++++++++++++++++++++++++++++++ src/ipsw.h | 2 + src/restore.c | 147 +++++++++++++++++-------------------------- 4 files changed, 201 insertions(+), 91 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 641eddb4..308c6cb2 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -2278,7 +2278,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie } /* add common tags from manifest */ - /* Adds Ap,OSLongVersion, AppNonce, @ApImg4Ticket */ + /* Adds Ap,OSLongVersion, ApNonce, @ApImg4Ticket */ if (tss_request_add_ap_img4_tags(request, parameters) < 0) { error("ERROR: Unable to add AP IMG4 tags to TSS request\n"); plist_free(request); diff --git a/src/ipsw.c b/src/ipsw.c index d4ee5e52..5c88c0d2 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -710,6 +710,147 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** return 0; } +int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx) +{ + unsigned char* buffer = NULL; + size_t done = 0; + size_t total_size = 0; + + ipsw_archive* archive = ipsw_open(ipsw); + if (archive == NULL) { + error("ERROR: Invalid archive\n"); + return -1; + } + + if (archive->zip) { + int zindex = zip_name_locate(archive->zip, infile, 0); + if (zindex < 0) { + debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); + ipsw_close(archive); + return -1; + } + + struct zip_stat zstat; + zip_stat_init(&zstat); + if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { + error("ERROR: zip_stat_index: %s\n", infile); + ipsw_close(archive); + return -1; + } + + struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); + if (zfile == NULL) { + error("ERROR: zip_fopen_index: %s\n", infile); + ipsw_close(archive); + return -1; + } + + total_size = zstat.size; + buffer = (unsigned char*) malloc(blocksize); + if (buffer == NULL) { + error("ERROR: Out of memory\n"); + zip_fclose(zfile); + ipsw_close(archive); + return -1; + } + + while (done < total_size) { + size_t size = total_size-done; + if (size > blocksize) size = blocksize; + zip_int64_t zr = zip_fread(zfile, buffer, size); + if (zr < 0) { + error("ERROR: %s: zip_fread: %s\n", __func__, infile); + break; + } else if (zr == 0) { + // EOF + break; + } + if (send_callback(ctx, buffer, zr) < 0) { + error("ERROR: %s: send failed\n", __func__); + break; + } + done += zr; + } + zip_fclose(zfile); + free(buffer); + } else { + char *filepath = build_path(archive->path, infile); + struct stat fst; +#ifdef WIN32 + if (stat(filepath, &fst) != 0) { +#else + if (lstat(filepath, &fst) != 0) { +#endif + error("ERROR: %s: stat failed for %s: %s\n", __func__, filepath, strerror(errno)); + free(filepath); + ipsw_close(archive); + return -1; + } + total_size = fst.st_size; + buffer = (unsigned char*)malloc(blocksize); + if (buffer == NULL) { + error("ERROR: Out of memory\n"); + free(filepath); + ipsw_close(archive); + return -1; + } + +#ifndef WIN32 + if (S_ISLNK(fst.st_mode)) { + ssize_t rl = readlink(filepath, (char*)buffer, (total_size > blocksize) ? blocksize : total_size); + if (rl < 0) { + error("ERROR: %s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno)); + free(filepath); + free(buffer); + ipsw_close(archive); + return -1; + } + send_callback(ctx, buffer, (size_t)rl); + } else { +#endif + FILE *f = fopen(filepath, "rb"); + if (!f) { + error("ERROR: %s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno)); + free(filepath); + free(buffer); + ipsw_close(archive); + return -2; + } + + while (done < total_size) { + size_t size = total_size-done; + if (size > blocksize) size = blocksize; + size_t fr = fread(buffer, 1, size, f); + if (fr != size) { + error("ERROR: %s: fread failed for %s: %s\n", __func__, filepath, strerror(errno)); + break; + } + if (send_callback(ctx, buffer, fr) < 0) { + error("ERROR: %s: send failed\n", __func__); + break; + } + done += fr; + } + fclose(f); +#ifndef WIN32 + } +#endif + free(filepath); + free(buffer); + } + ipsw_close(archive); + + if (done < total_size) { + error("ERROR: %s: Sending file data for %s failed (sent %" PRIu64 "/%" PRIu64 ")\n", __func__, infile, (uint64_t)done, (uint64_t)total_size); + return -1; + } + + // send a NULL buffer to mark end of transfer + send_callback(ctx, NULL, 0); + + return 0; +} + int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled) { unsigned int size = 0; diff --git a/src/ipsw.h b/src/ipsw.h index 3b5da80e..84ea7a9d 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -35,6 +35,7 @@ extern "C" { int ipsw_print_info(const char* ipsw); typedef int (*ipsw_list_cb)(void *ctx, const char* ipsw, const char *name, struct stat *stat); +typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size); int ipsw_is_directory(const char* ipsw); int ipsw_file_exists(const char* ipsw, const char* infile); @@ -42,6 +43,7 @@ int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size); int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfile); int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, const char* outfile, int print_progress); int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize); +int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx); int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled); int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist); int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx); diff --git a/src/restore.c b/src/restore.c index 17c9b24d..b0863801 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3326,18 +3326,18 @@ int extract_macos_variant(plist_t build_identity, char** output) return 0; } -int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, unsigned char** pbuffer, unsigned int* psize) +static char* extract_global_manifest_path(plist_t build_identity, char *variant) { plist_t build_info = plist_dict_get_item(build_identity, "Info"); if (!build_info) { error("ERROR: build identity does not contain an 'Info' element\n"); - return -1; + return NULL; } plist_t device_class_node = plist_dict_get_item(build_info, "DeviceClass"); if (!device_class_node) { error("ERROR: build identity info does not contain a DeviceClass\n"); - return -1; + return NULL; } char *device_class = NULL; plist_get_string_val(device_class_node, &device_class); @@ -3350,7 +3350,7 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil ret = extract_macos_variant(build_identity, &macos_variant); if (ret != 0) { free(device_class); - return -1; + return NULL; } } @@ -3361,7 +3361,17 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil free(device_class); free(macos_variant); - ret = ipsw_extract_to_memory(client->ipsw, ticket_path, pbuffer, psize); + return ticket_path; +} + +int extract_global_manifest(struct idevicerestore_client_t* client, plist_t build_identity, char *variant, unsigned char** pbuffer, unsigned int* psize) +{ + char* ticket_path = extract_global_manifest_path(build_identity, variant); + if (!ticket_path) { + error("ERROR: failed to get global manifest path\n"); + return -1; + } + int ret = ipsw_extract_to_memory(client->ipsw, ticket_path, pbuffer, psize); if (ret != 0) { free(ticket_path); error("ERROR: failed to read global manifest\n"); @@ -3372,6 +3382,26 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil return 0; } +static int _restore_send_file_data(restored_client_t restore, void* data, size_t size) +{ + plist_t dict = plist_new_dict(); + if (data != NULL) { + // Send a chunk of file data + plist_dict_set_item(dict, "FileData", plist_new_data((char*)data, size)); + } else { + // Send FileDataDone to mark end of transfer + plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); + } + restored_error_t restore_error = restored_send(restore, dict); + if (restore_error != RESTORE_E_SUCCESS) { + plist_free(dict); + error("ERROR: %s: Failed to send data (%d)\n", __func__, restore_error); + return -1; + } + plist_free(dict); + return 0; +} + int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity) { debug_plist(msg); @@ -3395,9 +3425,8 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i plist_t blob = NULL; plist_t dict = NULL; restored_error_t restore_error = RESTORE_E_SUCCESS; - char *component_name = component; - info("About to send %s...\n", component_name); + info("About to send %s...\n", component); if (strcmp(image_name, "__GlobalManifest__") == 0) { int ret = extract_global_manifest(client, build_identity, NULL, &data, &size); @@ -3446,7 +3475,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i return -1; } - // Personalize IMG40 + // Personalize IMG4 ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); free(component_data); component_data = NULL; @@ -3456,43 +3485,23 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i } } - // Make plist - info("Sending %s now...\n", component_name); + info("Sending %s now...\n", component); int64_t i = size; while (i > 0) { int blob_size = i > 8192 ? 8192 : i; - - dict = plist_new_dict(); - blob = plist_new_data((char *) (data + size - i), blob_size); - plist_dict_set_item(dict, "FileData", blob); - - restore_error = restored_send(restore, dict); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); + if (_restore_send_file_data(restore, (data + size - i), blob_size) < 0) { + free(data); + error("ERROR: Unable to send component %s data\n", component); return -1; } - - plist_free(dict); - i -= blob_size; } - debug("\n"); - - // Send FileDataDone - dict = plist_new_dict(); - plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); - - restore_error = restored_send(restore, dict); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); - return -1; - } - - plist_free(dict); free(data); - info("Done sending %s\n", component_name); + _restore_send_file_data(restore, NULL, 0); + + info("Done sending %s\n", component); return 0; } @@ -3521,9 +3530,8 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice plist_t blob = NULL; plist_t dict = NULL; restored_error_t restore_error = RESTORE_E_SUCCESS; - char *component_name = component; - info("About to send %s...\n", component_name); + info("About to send %s...\n", component); if (strcmp(image_name, "__GlobalManifest__") == 0) { char *variant = NULL; @@ -3538,22 +3546,11 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice return -1; } - int ret = extract_global_manifest(client, build_identity, variant, &data, &size); - if (ret != 0) { - return -1; - } + path = extract_global_manifest_path(build_identity, variant); } else if (strcmp(image_name, "__RestoreVersion__") == 0) { - int ret = ipsw_extract_to_memory(client->ipsw, "RestoreVersion.plist", &data, &size); - if (ret != 0) { - error("ERROR: failed to read global manifest\n"); - return -1; - } + path = strdup("RestoreVersion.plist"); } else if (strcmp(image_name, "__SystemVersion__") == 0) { - int ret = ipsw_extract_to_memory(client->ipsw, "SystemVersion.plist", &data, &size); - if (ret != 0) { - error("ERROR: failed to read global manifest\n"); - return -1; - } + path = strdup("SystemVersion.plist"); } else { // Get component path if (client->tss) { @@ -3568,53 +3565,23 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice return -1; } } - - int ret = extract_component(client->ipsw, path, &data, &size); - free(path); - path = NULL; - if (ret < 0) { - error("ERROR: Unable to extract component %s\n", component); - return -1; - } } - // Make plist - info("Sending %s now...\n", component_name); - - int64_t i = size; - while (i > 0) { - int blob_size = i > 8192 ? 8192 : i; - - dict = plist_new_dict(); - blob = plist_new_data((char *) (data + size - i), blob_size); - plist_dict_set_item(dict, "FileData", blob); - - restore_error = restored_send(restore, dict); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); - return -1; - } - - plist_free(dict); - - i -= blob_size; + if (!path) { + error("ERROR: Failed to get path for component %s\n", component); + return -1; } - debug("\n"); - // Send FileDataDone - dict = plist_new_dict(); - plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); + info("Sending %s now...\n", component); - restore_error = restored_send(restore, dict); - if (restore_error != RESTORE_E_SUCCESS) { - error("ERROR: Unable to send component %s data\n", component_name); + if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, restore) < 0) { + free(path); + error("ERROR: Failed to send component %s\n", component); return -1; } + free(path); - plist_free(dict); - free(data); - - info("Done sending %s\n", component_name); + info("Done sending %s\n", component); return 0; } From a4f5a0c1a65c9df239a737c350d4723c2a8cbc55 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 4 Oct 2022 13:06:20 +0200 Subject: [PATCH 011/117] img4: Add support for stitching with additional TBM data --- src/idevicerestore.c | 4 +- src/img4.c | 192 ++++++++++++++++++++++++++++++++++++++++++- src/img4.h | 2 +- 3 files changed, 191 insertions(+), 7 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 308c6cb2..62fbc09c 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -2566,9 +2566,9 @@ int personalize_component(const char *component_name, const unsigned char* compo unsigned char* stitched_component = NULL; unsigned int stitched_component_size = 0; - if (tss_response && tss_response_get_ap_img4_ticket(tss_response, &component_blob, &component_blob_size) == 0) { + if (tss_response && plist_dict_get_item(tss_response, "ApImg4Ticket")) { /* stitch ApImg4Ticket into IMG4 file */ - img4_stitch_component(component_name, component_data, component_size, component_blob, component_blob_size, &stitched_component, &stitched_component_size); + img4_stitch_component(component_name, component_data, component_size, tss_response, &stitched_component, &stitched_component_size); } else { /* try to get blob for current component from tss response */ if (tss_response && tss_response_get_blob_by_entry(tss_response, component_name, &component_blob) < 0) { diff --git a/src/img4.c b/src/img4.c index 6cff3497..3a74c5ef 100644 --- a/src/img4.c +++ b/src/img4.c @@ -24,6 +24,7 @@ #include "common.h" #include "img4.h" +#include "tss.h" #define ASN1_PRIVATE 0xc0 #define ASN1_PRIMITIVE_TAG 0x1f @@ -201,7 +202,7 @@ static void asn1_write_element(unsigned char **p, unsigned int *length, unsigned } } break; default: - fprintf(stderr, "ERROR: %s: type %02x is not implemented", __func__, type); + fprintf(stderr, "ERROR: %s: type %02x is not implemented\n", __func__, type); return; } } @@ -393,7 +394,38 @@ static const char *_img4_get_component_tag(const char *compname) return NULL; } -int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img4_data, unsigned int *img4_size) +static void hexdump(char* data, int length) +{ + int i; + int j; + unsigned char c; + + for (i = 0; i < length; i += 16) { + fprintf(stderr, "%04x: ", i); + for (j = 0; j < 16; j++) { + if (i + j >= length) { + fprintf(stderr, " "); + continue; + } + fprintf(stderr, "%02x ", *(data + i + j) & 0xff); + } + fprintf(stderr, " | "); + for (j = 0; j < 16; j++) { + if (i + j >= length) + break; + c = *(data + i + j); + if ((c < 32) || (c > 127)) { + fprintf(stderr, "."); + continue; + } + fprintf(stderr, "%c", c); + } + fprintf(stderr, "\n"); + } + fprintf(stderr, "\n"); +} + +int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size) { unsigned char* magic_header = NULL; unsigned int magic_header_size = 0; @@ -404,8 +436,15 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo unsigned int content_size; unsigned char* outbuf; unsigned char* p; + unsigned char* blob = NULL; + unsigned int blob_size = 0; - if (!component_name || !component_data || component_size == 0 || !blob || blob_size == 0 || !img4_data || !img4_size) { + if (!component_name || !component_data || component_size == 0 || !tss_response || !img4_data || !img4_size) { + return -1; + } + + if (tss_response_get_ap_img4_ticket(tss_response, &blob, &blob_size) != 0) { + error("ERROR: %s: Failed to get ApImg4Ticket from TSS response\n", __func__); return -1; } @@ -435,13 +474,152 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo } } + // check if we have a *-TBM entry for the given component + unsigned char *additional_data = NULL; + unsigned int additional_size = 0; + char *tbm_key = malloc(strlen(component_name) + 5); + sprintf(tbm_key, "%s-TBM", component_name); + plist_t tbm_dict = plist_dict_get_item(tss_response, tbm_key); + free(tbm_key); + if (tbm_dict) { + plist_t dt = plist_dict_get_item(tbm_dict, "ucon"); + if (!dt) { + error("ERROR: %s: Missing ucon node in %s-TBM dictionary\n", __func__, component_name); + return -1; + } + uint64_t ucon_size = 0; + const char* ucon_data = plist_get_data_ptr(dt, &ucon_size); + if (!ucon_data) { + error("ERROR: %s: Missing ucon data in %s-TBM dictionary\n", __func__, component_name); + return -1; + } + dt = plist_dict_get_item(tbm_dict, "ucer"); + if (!dt) { + error("ERROR: %s: Missing ucer data node in %s-TBM dictionary\n", __func__, component_name); + return -1; + } + uint64_t ucer_size = 0; + const char* ucer_data = plist_get_data_ptr(dt, &ucer_size); + if (!ucer_data) { + error("ERROR: %s: Missing ucer data in %s-TBM dictionary\n", __func__, component_name); + return -1; + } + + unsigned char *im4rset = (unsigned char*)malloc(16 + 8 + 8 + ucon_size + 16 + 8 + 8 + ucer_size + 16); + unsigned char *p_im4rset = im4rset; + unsigned int im4rlen = 0; + + // ----------- ucon ------------ + // write priv ucon element + asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"nocu"); + + // write ucon IA5STRING and ucon data + unsigned char ucon_seq[16]; + unsigned char *p_ucon_seq = &ucon_seq[0]; + unsigned int ucon_seq_hdr_len = 0; + asn1_write_element(&p_ucon_seq, &ucon_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucon", -1); + asn1_write_element_header(ASN1_OCTET_STRING, ucon_size, &p_ucon_seq, &ucon_seq_hdr_len); + + // write ucon sequence + unsigned char elem_seq[8]; + unsigned char *p = &elem_seq[0]; + unsigned int seq_hdr_len = 0; + asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, ucon_seq_hdr_len + ucon_size, &p, &seq_hdr_len); + + // add size to priv ucon element + asn1_write_size(ucon_seq_hdr_len + ucon_size + seq_hdr_len, &p_im4rset, &im4rlen); + + // put it together + memcpy(p_im4rset, elem_seq, seq_hdr_len); + p_im4rset += seq_hdr_len; + im4rlen += seq_hdr_len; + memcpy(p_im4rset, ucon_seq, ucon_seq_hdr_len); + p_im4rset += ucon_seq_hdr_len; + im4rlen += ucon_seq_hdr_len; + memcpy(p_im4rset, ucon_data, ucon_size); + p_im4rset += ucon_size; + im4rlen += ucon_size; + + // ----------- ucer ------------ + // write priv ucer element + asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"recu"); + + // write ucon IA5STRING and ucer data + unsigned char ucer_seq[16]; + unsigned char *p_ucer_seq = &ucer_seq[0]; + unsigned int ucer_seq_hdr_len = 0; + asn1_write_element(&p_ucer_seq, &ucer_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucer", -1); + asn1_write_element_header(ASN1_OCTET_STRING, ucer_size, &p_ucer_seq, &ucer_seq_hdr_len); + + p = &elem_seq[0]; + seq_hdr_len = 0; + asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, ucer_seq_hdr_len + ucer_size, &p, &seq_hdr_len); + + // add size to priv ucer element + asn1_write_size(ucer_seq_hdr_len + ucer_size + seq_hdr_len, &p_im4rset, &im4rlen); + + // put it together + memcpy(p_im4rset, elem_seq, seq_hdr_len); + p_im4rset += seq_hdr_len; + im4rlen += seq_hdr_len; + memcpy(p_im4rset, ucer_seq, ucer_seq_hdr_len); + p_im4rset += ucer_seq_hdr_len; + im4rlen += ucer_seq_hdr_len; + memcpy(p_im4rset, ucer_data, ucer_size); + p_im4rset += ucer_size; + im4rlen += ucer_size; + + // now construct IM4R + + /* write inner set */ + unsigned char inner_set_[8]; + unsigned char *inner_set = &inner_set_[0]; + unsigned int inner_set_len = 0; + asn1_write_element_header(ASN1_SET | ASN1_CONSTRUCTED, im4rlen, &inner_set, &inner_set_len); + + /* write header values */ + unsigned char hdrdata_[16]; + unsigned char *hdrdata = &hdrdata_[0]; + unsigned int hdrdata_len = 0; + asn1_write_element(&hdrdata, &hdrdata_len, ASN1_IA5_STRING, (void*)"IM4R", -1); + + /* write sequence now that we know the entire size */ + unsigned char seq_[8]; + unsigned char *seq = &seq_[0]; + unsigned int seq_len = 0; + asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, im4rlen + inner_set_len + hdrdata_len, &seq, &seq_len); + + /* write outer cont[1] */ + unsigned char cont_[8]; + unsigned char *cont = &cont_[0]; + unsigned int cont_len = 0; + asn1_write_element_header(ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1, im4rlen + inner_set_len + hdrdata_len + seq_len, &cont, &cont_len); + + // now put everything together + additional_data = malloc(im4rlen + inner_set_len + hdrdata_len + seq_len + cont_len); + p = additional_data; + memcpy(p, cont_, cont_len); + p += cont_len; + memcpy(p, seq_, seq_len); + p += seq_len; + memcpy(p, hdrdata_, hdrdata_len); + p += hdrdata_len; + memcpy(p, inner_set_, inner_set_len); + p += inner_set_len; + memcpy(p, im4rset, im4rlen); + p += im4rlen; + additional_size = (unsigned int)(p - additional_data); + + free(im4rset); + } + // create element header for the "IMG4" magic asn1_create_element_header(ASN1_IA5_STRING, IMG4_MAGIC_SIZE, &magic_header, &magic_header_size); // create element header for the blob (ApImg4Ticket) asn1_create_element_header(ASN1_CONTEXT_SPECIFIC|ASN1_CONSTRUCTED, blob_size, &blob_header, &blob_header_size); // calculate the size for the final IMG4 file (asn1 sequence) - content_size = magic_header_size + IMG4_MAGIC_SIZE + component_size + blob_header_size + blob_size; + content_size = magic_header_size + IMG4_MAGIC_SIZE + component_size + blob_header_size + blob_size + additional_size; // create element header for the final IMG4 asn1 blob asn1_create_element_header(ASN1_SEQUENCE|ASN1_CONSTRUCTED, content_size, &img4header, &img4header_size); @@ -457,6 +635,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo if (img4header) { free(img4header); } + free(additional_data); error("ERROR: out of memory when personalizing IMG4 component %s\n", component_name); return -1; } @@ -475,6 +654,10 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo p += blob_header_size; memcpy(p, blob, blob_size); p += blob_size; + if (additional_size) { + memcpy(p, additional_data, additional_size); + p += additional_size; + } *img4_data = outbuf; *img4_size = (p - outbuf); @@ -488,6 +671,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo if (img4header) { free(img4header); } + free(additional_data); return 0; } diff --git a/src/img4.h b/src/img4.h index 37dea569..1056fa68 100644 --- a/src/img4.h +++ b/src/img4.h @@ -26,7 +26,7 @@ extern "C" { #endif -int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img4_data, unsigned int *img4_size); +int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size); int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* manifest); #ifdef __cplusplus From c45f74cc3e075d3b04dd920141e82a51dc20bd9b Mon Sep 17 00:00:00 2001 From: Munehisa Kamata Date: Tue, 4 Oct 2022 21:52:20 -0700 Subject: [PATCH 012/117] recovery: set bRequest to 1 when sending bootx command In macOS 13 beta 8 or newer release, bootx seems to fail if bRequest is 0 in the control transfer setup. Then, the device fails to enter restore mode. Seems like something has changed in iBEC since beta 8 and Apple Configurator 2 has set it to 1, so do the same thing. While this could be applied for all *OS variants, it's limited to macOS for now just to be safe. Signed-off-by: Munehisa Kamata --- src/recovery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/recovery.c b/src/recovery.c index 1a9c9709..24d0c3d0 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -498,7 +498,7 @@ int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t bu recovery_error = irecv_send_command(client->recovery->client, setba); } - recovery_error = irecv_send_command(client->recovery->client, "bootx"); + recovery_error = irecv_send_command_breq(client->recovery->client, "bootx", client->macos_variant ? 1 : 0); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); return -1; From 4e46f12b52207cae9a4733e72534a1309870351b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 7 Oct 2022 17:19:34 +0200 Subject: [PATCH 013/117] [github-actions] Fix MinGW build --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a573678f..6bd25bc5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -271,7 +271,7 @@ jobs: echo "LIBZIP_CFLAGS=-I`pwd`/deps/include" >> $GITHUB_ENV echo "LIBZIP_LIBS=`pwd`/deps/lib/libzip.a /${{env.dest}}/lib/libbz2.a /${{env.dest}}/lib/liblzma.a " >> $GITHUB_ENV - name: autogen - run: ./autogen.sh CC=gcc CXX=g++ --without-openssl libzip_CFLAGS="${{env.LIBZIP_CFLAGS}}" libzip_LIBS="${{env.LIBZIP_LIBS}}" zlib_LIBS="/${{env.dest}}/lib/libz.a" + run: ./autogen.sh CC=gcc CXX=g++ --without-openssl libzip_VERSION=1.7.1 libzip_CFLAGS="${{env.LIBZIP_CFLAGS}}" libzip_LIBS="${{env.LIBZIP_LIBS}}" zlib_LIBS="/${{env.dest}}/lib/libz.a" - name: make run: make - name: make install From 961077074cf4f113d685ce19f3e0b18d343a74d6 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 8 Oct 2022 21:15:18 +0200 Subject: [PATCH 014/117] recovery: Send bootx with bRequest set to 1 for all platforms --- src/recovery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/recovery.c b/src/recovery.c index 24d0c3d0..59cce625 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -498,7 +498,7 @@ int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t bu recovery_error = irecv_send_command(client->recovery->client, setba); } - recovery_error = irecv_send_command_breq(client->recovery->client, "bootx", client->macos_variant ? 1 : 0); + recovery_error = irecv_send_command_breq(client->recovery->client, "bootx", 1); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); return -1; From f6950c2461b28333bcef84a98f2132e93b216faf Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 11 Oct 2022 12:46:12 +0200 Subject: [PATCH 015/117] recovery: Also send "go" and "reset" commands with bRequest set to 1 --- src/recovery.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/recovery.c b/src/recovery.c index 59cce625..a9d6b61f 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -344,7 +344,7 @@ int recovery_send_ibec(struct idevicerestore_client_t* client, plist_t build_ide return -1; } - recovery_error = irecv_send_command(client->recovery->client, "go"); + recovery_error = irecv_send_command_breq(client->recovery->client, "go", 1); if (recovery_error != IRECV_E_SUCCESS) { error("ERROR: Unable to execute %s\n", component); return -1; @@ -575,7 +575,7 @@ int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char int recovery_send_reset(struct idevicerestore_client_t* client) { - irecv_send_command(client->recovery->client, "reset"); + irecv_send_command_breq(client->recovery->client, "reset", 1); return 0; } From f8a92587b656a0ef793e9057fafdb67cf00a188d Mon Sep 17 00:00:00 2001 From: Alfie Cockell Gwinnett Date: Tue, 11 Oct 2022 18:05:08 +0100 Subject: [PATCH 016/117] Check if device is limera1n-vulnerable for --pwn option --- src/idevicerestore.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 62fbc09c..186595b8 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -482,17 +482,39 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (dfu_client_new(client) < 0) { return -1; } - info("exploiting with limera1n...\n"); - // TODO: check for non-limera1n device and fail - if (limera1n_exploit(client->device, &client->dfu->client) != 0) { - error("ERROR: limera1n exploit failed\n"); + + // Check if device is vulnerable to limera1n + unsigned int cpid = 0; + dfu_get_cpid(client, &cpid); + + int limera1nDevices[] = {8920, 8922, 8930}; + int limera1nDevicesLen = sizeof limera1nDevices / sizeof limera1nDevices[0]; + int limera1nVuln = 0; + + for (int i = 0; i < limera1nDevicesLen; i++) { + if (limera1nDevices[i] == cpid) { + limera1nVuln = 1; + break; + } + } + + if (limera1nVuln == 1) { + info("exploiting with limera1n...\n"); + if (limera1n_exploit(client->device, &client->dfu->client) != 0) { + error("ERROR: limera1n exploit failed\n"); + dfu_client_free(client); + return -1; + } + dfu_client_free(client); + info("Device should be in pwned DFU state now.\n"); + + return 0; + } + else { dfu_client_free(client); + error("ERROR: This device is not supported by the limera1n exploit"); return -1; } - dfu_client_free(client); - info("Device should be in pwned DFU state now.\n"); - - return 0; } if (client->flags & FLAG_LATEST) { From d20eb2135be46a3596d4f5c97f175faa96c55929 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 18 Oct 2022 01:09:44 +0200 Subject: [PATCH 017/117] Use limera1n_is_supported instead of compatibility check added with previous commit --- src/idevicerestore.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 186595b8..3d6b65c2 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -483,22 +483,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } - // Check if device is vulnerable to limera1n - unsigned int cpid = 0; - dfu_get_cpid(client, &cpid); - - int limera1nDevices[] = {8920, 8922, 8930}; - int limera1nDevicesLen = sizeof limera1nDevices / sizeof limera1nDevices[0]; - int limera1nVuln = 0; - - for (int i = 0; i < limera1nDevicesLen; i++) { - if (limera1nDevices[i] == cpid) { - limera1nVuln = 1; - break; - } - } - - if (limera1nVuln == 1) { + if (limera1n_is_supported(client->device)) { info("exploiting with limera1n...\n"); if (limera1n_exploit(client->device, &client->dfu->client) != 0) { error("ERROR: limera1n exploit failed\n"); @@ -1246,7 +1231,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } info("exploiting with limera1n\n"); - // TODO: check for non-limera1n device and fail if (limera1n_exploit(client->device, &client->dfu->client) != 0) { error("ERROR: limera1n exploit failed\n"); dfu_client_free(client); From 2a907b0eaf3549382127aa811830ca72a553ccb8 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 19 Oct 2022 05:38:59 +0200 Subject: [PATCH 018/117] restore: Only print boot object v3/v4 plist in debug mode --- src/restore.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/restore.c b/src/restore.c index b0863801..e8913f54 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3404,7 +3404,10 @@ static int _restore_send_file_data(restored_client_t restore, void* data, size_t int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity) { - debug_plist(msg); + if (idevicerestore_debug) { + debug("DEBUG: %s: Got PersonalizedBootObjectV3 request:\n", __func__); + debug_plist(message); + } char *image_name = NULL; plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName"); @@ -3507,7 +3510,10 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i int restore_send_source_boot_object_v4(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity) { - debug_plist(msg); + if (idevicerestore_debug) { + debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__); + debug_plist(message); + } char *image_name = NULL; plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName"); From 7b89019fbb81ce64e1c1d259c5746544c8e8eeea Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 19 Oct 2022 08:32:58 +0200 Subject: [PATCH 019/117] restore: Fix compilation error due to wrong variable name --- src/restore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/restore.c b/src/restore.c index e8913f54..69f2f099 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3406,7 +3406,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i { if (idevicerestore_debug) { debug("DEBUG: %s: Got PersonalizedBootObjectV3 request:\n", __func__); - debug_plist(message); + debug_plist(msg); } char *image_name = NULL; @@ -3512,7 +3512,7 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice { if (idevicerestore_debug) { debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__); - debug_plist(message); + debug_plist(msg); } char *image_name = NULL; From bc617712ed2fdda6338e9f057ba7396d424d88e4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 13 Apr 2023 00:33:13 +0200 Subject: [PATCH 020/117] img4: Remove unused debug code --- src/img4.c | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/src/img4.c b/src/img4.c index 3a74c5ef..c21a0753 100644 --- a/src/img4.c +++ b/src/img4.c @@ -394,37 +394,6 @@ static const char *_img4_get_component_tag(const char *compname) return NULL; } -static void hexdump(char* data, int length) -{ - int i; - int j; - unsigned char c; - - for (i = 0; i < length; i += 16) { - fprintf(stderr, "%04x: ", i); - for (j = 0; j < 16; j++) { - if (i + j >= length) { - fprintf(stderr, " "); - continue; - } - fprintf(stderr, "%02x ", *(data + i + j) & 0xff); - } - fprintf(stderr, " | "); - for (j = 0; j < 16; j++) { - if (i + j >= length) - break; - c = *(data + i + j); - if ((c < 32) || (c > 127)) { - fprintf(stderr, "."); - continue; - } - fprintf(stderr, "%c", c); - } - fprintf(stderr, "\n"); - } - fprintf(stderr, "\n"); -} - int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size) { unsigned char* magic_header = NULL; From d291eb107d68ca53e9b19a169725515eae72aae5 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 14 Apr 2023 03:52:14 +0200 Subject: [PATCH 021/117] Allow setting custom TSS request URL through command line switch --- src/idevicerestore.c | 39 +++++++++++++++++++++++++++++++++------ src/tss.c | 1 + 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 3d6b65c2..466cfe2e 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -72,7 +72,7 @@ static struct option longopts[] = { { "erase", no_argument, NULL, 'e' }, { "custom", no_argument, NULL, 'c' }, { "latest", no_argument, NULL, 'l' }, - { "cydia", no_argument, NULL, 's' }, + { "server", required_argument, NULL, 's' }, { "exclude", no_argument, NULL, 'x' }, { "shsh", no_argument, NULL, 't' }, { "keep-pers", no_argument, NULL, 'k' }, @@ -132,8 +132,8 @@ static void usage(int argc, char* argv[], int err) "\n" \ "Advanced/experimental options:\n" " -c, --custom Restore with a custom firmware (requires bootrom exploit)\n" \ - " -s, --cydia Use Cydia's signature service instead of Apple's\n" \ - " -x, --exclude Exclude nor/baseband upgrade\n" \ + " -s, --server URL Override default signing server request URL\n" \ + " -x, --exclude Exclude nor/baseband upgrade (legacy devices)\n" \ " -t, --shsh Fetch TSS record and save to .shsh file, then exit\n" \ " -z, --no-restore Do not restore and end after booting to the ramdisk\n" \ " -k, --keep-pers Write personalized components to files for debugging\n" \ @@ -1617,7 +1617,7 @@ int main(int argc, char* argv[]) { client->flags |= FLAG_INTERACTIVE; } - while ((opt = getopt_long(argc, argv, "dhcesxtpli:u:nC:kyPRT:zv", longopts, &optindex)) > 0) { + while ((opt = getopt_long(argc, argv, "dhces:xtpli:u:nC:kyPRT:zv", longopts, &optindex)) > 0) { switch (opt) { case 'h': usage(argc, argv, 0); @@ -1635,8 +1635,35 @@ int main(int argc, char* argv[]) { client->flags |= FLAG_CUSTOM; break; - case 's': - client->tss_url = strdup("http://cydia.saurik.com/TSS/controller?action=2"); + case 's': { + if (!*optarg) { + error("ERROR: URL argument for --server must not be empty!\n"); + usage(argc, argv, 1); + return EXIT_FAILURE; + } + char *baseurl = NULL; + if (!strncmp(optarg, "http://", 7) && (strlen(optarg) > 7) && (optarg[7] != '/')) { + baseurl = optarg+7; + } else if (!strncmp(optarg, "https://", 8) && (strlen(optarg) > 8) && (optarg[8] != '/')) { + baseurl = optarg+8; + } + if (baseurl) { + char *p = strchr(baseurl, '/'); + if (!p || *(p+1) == '\0') { + // no path component, add default path + const char default_path[] = "/TSS/controller?action=2"; + char* newurl = malloc(strlen(optarg)+sizeof(default_path)); + sprintf(newurl, "%s%s", optarg, (p) ? default_path+1 : default_path); + client->tss_url = newurl; + } else { + client->tss_url = strdup(optarg); + } + } else { + error("ERROR: URL argument for --server is invalid, must start with http:// or https://\n"); + usage(argc, argv, 1); + return EXIT_FAILURE; + } + } break; case 'x': diff --git a/src/tss.c b/src/tss.c index da4cf178..e1cf1f4a 100644 --- a/src/tss.c +++ b/src/tss.c @@ -1524,6 +1524,7 @@ plist_t tss_request_send(plist_t tss_request, const char* server_url_string) curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, strlen(request)); if (server_url_string) { curl_easy_setopt(handle, CURLOPT_URL, server_url_string); + info("Request URL set to %s\n", server_url_string); } else { int url_index = (retry - 1) % 6; curl_easy_setopt(handle, CURLOPT_URL, urls[url_index]); From 1ec7bb430971341f16e7f0f6a8670d2f5b850ff8 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 14 Apr 2023 03:53:06 +0200 Subject: [PATCH 022/117] docs: Updated man page --- docs/idevicerestore.1 | 109 +++++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 32 deletions(-) diff --git a/docs/idevicerestore.1 b/docs/idevicerestore.1 index 8e0a8845..d1415482 100644 --- a/docs/idevicerestore.1 +++ b/docs/idevicerestore.1 @@ -1,66 +1,111 @@ .TH "idevicerestore" 1 .SH NAME -idevicerestore \- Restore IPSW firmware FILE to an iOS device +idevicerestore \- Restore IPSW firmware at PATH to an iOS device .SH SYNOPSIS .B idevicerestore -[OPTIONS] FILE +[OPTIONS] PATH .SH DESCRIPTION Restore firmware files to iOS devices while either erasing the device or updating to preserve content and settings. +\f[B]PATH\f[] can be a compressed .ipsw file or a directory containing all files extracted from an IPSW. + .SH OPTIONS .TP .B \-i, \-\-ecid ECID -target specific device by its hexadecimal ECID e.g. 0xaabb123456 or 00000012AABBCCDD. +Target specific device by its ECID, e.g. 0xaabb123456 (hex) or 1234567890 (decimal). .TP .B \-u, \-\-udid UDID -target specific device by its 40-digit device UDID. -NOTE: only works with devices in normal mode. +Target specific device by its device UDID. + +\f[B]NOTE\f[]: only works with devices in normal mode. .TP +.B \-l, \-\-latest +Use latest available firmware (with download on demand). +Before performing any action it will interactively ask +to select one of the currently signed firmware versions, +unless \f[B]\-y\f[] has been given too. + +The PATH argument is ignored when using this option. + +\f[B]DO NOT USE\f[] if you need to preserve the baseband/unlock! + +\f[B]USE WITH CARE\f[] if you want to keep a jailbreakable firmware! +.TP .B \-e, \-\-erase -perform a full restore, erasing all data (defaults to update). +Perform full restore instead of update, erasing all data + +\f[B]DO NOT USE\f[] if you want to preserve user data on the device! +.TP +.B \-y, \-\-no\-input +Non-interactive mode, do not ask for any input. + +\f[B]WARNING\f[]: This will disable certain checks/prompts that are supposed +to prevent DATA LOSS. \f[B]Use with caution\f[]. +.TP +.B \-n, \-\-no\-action +Do not perform any restore action. If combined with \f[B]\-l\f[] option +the on-demand ipsw download is performed before exiting. +.TP +.B \-\-ipsw\-info +Print information about the IPSW at PATH and exit. +.TP +.B \-h, \-\-help +Prints usage information. +.TP +.B \-C, \-\-cache\-path DIR +Use specified directory for caching extracted or other reused files. +.TP +.B \-d, \-\-debug +Enable communication debugging. +.TP +.B \-v, \-\-version +Prints version information. + +.SH ADVANCED/EXPERIMENTAL OPTIONS .TP .B \-c, \-\-custom -restore with a custom firmware. -.TP -.B \-l, \-\-latest -use latest available firmware (with download on demand). \ -DO NOT USE if you need to preserve the baseband (unlock)! \ -USE WITH CARE if you want to keep a jailbreakable firmware! \ -The FILE argument is ignored when using this option. +Restore with a custom firmware (requires bootrom exploit) .TP -.B \-s, \-\-cydia -use Cydia's signature service instead of Apple's. +.B \-s, \-\-server URL +Override the default signing server request URL. If the URL doesn't contain +a path component, the default path \f[B]/TSS/controller?action=2\f[] will be added. .TP .B \-x, \-\-exclude -exclude nor/baseband upgrade. +Exclude nor/baseband upgrade. + +\f[B]NOTE\f[]: This option only works with legacy devices and/or custom firmware. .TP .B \-t, \-\-shsh -fetch TSS record and save to .shsh file, then exit. +Fetch TSS record and save to .shsh file, then exit. .TP -.B \-p, \-\-pwn -put device in pwned DFU mode and exit (limera1n devices only). +.B \-z, \-\-no\-restore +Do not restore and end after booting to the ramdisk. .TP -.B \-n, \-\-no\-action -do not perform any restore action. If combined with -l option the on demand -IPSW download is performed before exiting. +.B \-k, \-\-keep\-pers +Write personalized components to files for debugging. .TP -.B \-\-ipsw\-info -Print information about the IPSW at PATH and exit. +.B \-p, \-\-pwn +Put device in pwned DFU mode and exit (limera1n devices only). .TP -.B \-C, \-\-cache\-path DIR -use specified directory for caching extracted or other reused files. +.B \-P, --plain-progress +Print progress as plain step and progress .TP -.B \-d, \-\-debug -enable communication debugging. +.B \-R, \-\-restore\-mode +Allow restoring from Restore mode .TP -.B \-h, \-\-help -prints usage information. +.B \-T, \-\-ticket PATH +Use file at PATH to send as AP ticket .TP -.B \-v, \-\-version -prints version information. +.B \-\-variant VARIANT +Use given VARIANT to match the build identity to use, e.g. 'Customer Erase Install (IPSW)' +.TP +.B \-\-ignore\-errors +Try to continue the restore process after certain errors (like a failed baseband update). + +\f[B]WARNING\f[]: This might render the device unable to boot or only partially functioning. \f[B]Use with caution\f[]. .SH AUTHORS Martin Szulecki From 7321192b1bd3781ca214f575d63e2df4b0fdade2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 21 Apr 2023 17:25:05 +0200 Subject: [PATCH 023/117] Updated to use latest libplist API --- configure.ac | 2 +- src/ipsw.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 38152756..cadd48eb 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ fi # Minimum package versions LIBIRECOVERY_VERSION=1.0.1 LIBIMOBILEDEVICE_VERSION=1.3.0 -LIBPLIST_VERSION=2.2.0 +LIBPLIST_VERSION=2.3.0 LIMD_GLUE_VERSION=1.0.0 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 diff --git a/src/ipsw.c b/src/ipsw.c index 5c88c0d2..fafe5830 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -134,7 +134,7 @@ int ipsw_print_info(const char* path) } plist_t manifest = NULL; - plist_from_memory(plist_buf, plist_len, &manifest); + plist_from_memory(plist_buf, plist_len, &manifest, NULL); free(plist_buf); plist_t val; From a851716c8430c7436559f3e74d7ad8cb2089fdcd Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 30 Apr 2023 16:43:59 +0200 Subject: [PATCH 024/117] git-version-gen: Prevent multiple lines of output --- git-version-gen | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/git-version-gen b/git-version-gen index 3eb6a42e..d8689526 100755 --- a/git-version-gen +++ b/git-version-gen @@ -3,7 +3,7 @@ SRCDIR=`dirname $0` if test -n "$1"; then VER=$1 else - if test -d "${SRCDIR}/.git" && test -x "`which git`" ; then + if test -r "${SRCDIR}/.git" && test -x "`which git`" ; then git update-index -q --refresh if ! VER=`git describe --tags --dirty 2>/dev/null`; then COMMIT=`git rev-parse --short HEAD` @@ -16,4 +16,5 @@ else fi fi fi +VER=`printf %s "$VER" | head -n1` printf %s "$VER" From 163a1647dedb7ca4656c0f072e4733573f9f982b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 30 Apr 2023 16:44:23 +0200 Subject: [PATCH 025/117] Make sure git-version-gen and .tarball-version are included in dist tarball --- Makefile.am | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 435cb17b..c86bf426 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,4 +4,8 @@ SUBDIRS = src docs EXTRA_DIST = \ docs \ - README.md + README.md \ + git-version-gen + +dist-hook: + echo $(VERSION) > $(distdir)/.tarball-version From 609f7f058487596597e8e742088119fdd46729df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Decoodt?= Date: Wed, 1 Mar 2023 20:33:47 +0100 Subject: [PATCH 026/117] Use DeviceGeneratedRequest plist for SE TSS requests --- src/restore.c | 23 +++++++++++++++++------ src/tss.c | 7 +++++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/restore.c b/src/restore.c index 69f2f099..486ffb56 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2105,7 +2105,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest return 0; } -static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) { const char *comp_name = NULL; char *comp_path = NULL; @@ -2114,6 +2114,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; + plist_t p_dgr = NULL; int ret; uint64_t chip_id = 0; plist_t node = plist_dict_get_item(p_info, "SE,ChipID"); @@ -2137,6 +2138,14 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id debug("DEBUG: %s: using %s\n", __func__, comp_name); } + p_dgr = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (!p_dgr) { + info("NOTE: %s: No DeviceGeneratedRequest in firmware updater data request. Continuing anyway.\n", __func__); + } else if (!PLIST_IS_DICT(p_dgr)) { + error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + 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; @@ -2167,7 +2176,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id plist_dict_merge(¶meters, p_info); /* add required tags for SE TSS request */ - tss_request_add_se_tags(request, parameters, NULL); + tss_request_add_se_tags(request, parameters, p_dgr); plist_free(parameters); @@ -2180,10 +2189,12 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id return NULL; } - if (plist_dict_get_item(response, "SE,Ticket")) { - info("Received SE ticket\n"); + if (plist_dict_get_item(response, "SE2,Ticket")) { + info("Received SE2,Ticket\n"); + } else if (plist_dict_get_item(response, "SE,Ticket")) { + info("Received SE,Ticket\n"); } else { - error("ERROR: No 'SE,Ticket' in TSS response, this might not work\n"); + error("ERROR: No 'SE 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)); @@ -3025,7 +3036,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct plist_get_string_val(p_updater_name, &s_updater_name); if (strcmp(s_updater_name, "SE") == 0) { - fwdict = restore_get_se_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_se_firmware_data(restore, client, build_identity, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get SE firmware data\n", __func__); goto error_out; diff --git a/src/tss.c b/src/tss.c index e1cf1f4a..9fb74af3 100644 --- a/src/tss.c +++ b/src/tss.c @@ -786,9 +786,7 @@ int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrid return -1; } - /* add tags indicating we want to get the SE,Ticket */ plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_set_item(request, "@SE,Ticket", plist_new_bool(1)); if (_plist_dict_copy_uint(request, parameters, "SE,ChipID", NULL) < 0) { error("ERROR: %s: Unable to find required SE,ChipID in parameters\n", __func__); @@ -864,6 +862,11 @@ int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrid plist_dict_merge(&request, overrides); } + /* fallback in case no @SE2,Ticket or @SE,Ticket was provided */ + if (!plist_dict_get_item(request, "@SE2,Ticket") && !plist_dict_get_item(request, "@SE,Ticket")) { + plist_dict_set_item(request, "@SE,Ticket", plist_new_bool(1)); + } + return 0; } From 73438a6ff3fe5758e927c05d389d0e9587dcbb50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Decoodt?= Date: Tue, 25 Jul 2023 15:12:32 +0200 Subject: [PATCH 027/117] Add support for incoherent iBoot parameters Some firmwares to load during iBoot stage 1 can have both: - isLoadedByiBoot = false - isLoadedByiBootStage1 = true This allows to load it at stage 1 --- src/dfu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index cb4d2b33..0c3c480a 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -349,11 +349,13 @@ int dfu_send_iboot_stage1_components(struct idevicerestore_client_t* client, pli uint8_t b = 0; plist_get_bool_val(iboot_node, &b); if (b) { - debug("DEBUG: %s is loaded by iBoot Stage 1.\n", key); - if (dfu_send_component_and_command(client, build_identity, key, "firmware") < 0) { - error("ERROR: Unable to send component '%s' to device.\n", key); - err++; - } + debug("DEBUG: %s is loaded by iBoot Stage 1 and iBoot.\n", key); + } else { + debug("DEBUG: %s is loaded by iBoot Stage 1 but not iBoot...\n", key); + } + if (dfu_send_component_and_command(client, build_identity, key, "firmware") < 0) { + error("ERROR: Unable to send component '%s' to device.\n", key); + err++; } } free(key); From da22dd466548a776a62208e060017aa6cdc2df52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Decoodt?= Date: Tue, 25 Jul 2023 15:17:49 +0200 Subject: [PATCH 028/117] Display iBoot boot stage This helps debugging cases where the iDevice does not go into stage 2 because of a missing firmware --- src/dfu.c | 15 +++++++++++++++ src/recovery.c | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/dfu.c b/src/dfu.c index 0c3c480a..4487ade0 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -473,6 +473,21 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide return -1; } + char *value = NULL; + unsigned long boot_stage = 0; + irecv_getenv(client->dfu->client, "boot-stage", &value); + if (value) { + boot_stage = strtoul(value, NULL, 0); + } + if (boot_stage > 0) { + info("iBoot boot-stage=%s\n", value); + free(value); + value = NULL; + if (boot_stage != 1) { + error("ERROR: iBoot should be at boot stage 1, continuing anyway...\n"); + } + } + if (dfu_send_iboot_stage1_components(client, build_identity) < 0) { mutex_unlock(&client->device_event_mutex); error("ERROR: Unable to send iBoot stage 1 components to device\n"); diff --git a/src/recovery.c b/src/recovery.c index a9d6b61f..02f56898 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -158,6 +158,20 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build free(value); value = NULL; + unsigned long boot_stage = 0; + irecv_getenv(client->recovery->client, "boot-stage", &value); + if (value) { + boot_stage = strtoul(value, NULL, 0); + } + if (boot_stage > 0) { + info("iBoot boot-stage=%s\n", value); + free(value); + value = NULL; + if (boot_stage != 2) { + error("ERROR: iBoot should be at boot stage 2, continuing anyway...\n"); + } + } + unsigned long radio_error = 0; irecv_getenv(client->recovery->client, "radio-error", &value); if (value) { From a3515134e1be6596d8a3775d6210085056885a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Decoodt?= Date: Tue, 25 Jul 2023 18:02:07 +0200 Subject: [PATCH 029/117] Add SE,ChipID 0x2C --- src/restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 486ffb56..2fd0ad10 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2123,7 +2123,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id } if (chip_id == 0x20211) { comp_name = "SE,Firmware"; - } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2) { + } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C) { comp_name = "SE,UpdatePayload"; } else { info("WARNING: Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id); From ed5463a4696a9e059562d6c2386dfa31eafa95a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Decoodt?= Date: Tue, 25 Jul 2023 18:02:27 +0200 Subject: [PATCH 030/117] Add generic TSS request generator This uses the DeviceGeneratedRequest and DeviceGeneratedTags to generate the full TSS request. This allows to have a more future-proof approach to new firmware names they add. --- src/restore.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/src/restore.c b/src/restore.c index 2fd0ad10..0699be7a 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2611,6 +2611,61 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str return response; } +static plist_t restore_get_generic_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +{ + plist_t request = NULL; + plist_t response = NULL; + + plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName"); + const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL); + + plist_t response_tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags"); + const char* response_ticket = NULL; + if (PLIST_IS_ARRAY(response_tags)) { + plist_t tag0 = plist_array_get_item(response_tags, 0); + if (tag0) { + response_ticket = plist_get_string_ptr(tag0, NULL); + } + } + if (response_ticket == NULL) { + error("ERROR: Unable to determine response ticket from device generated tags"); + return NULL; + } + + /* create TSS request */ + request = tss_request_new(NULL); + if (request == NULL) { + error("ERROR: Unable to create %s TSS request\n", s_updater_name); + return NULL; + } + + /* add device generated request data to request */ + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (!device_generated_request) { + error("ERROR: Could not find DeviceGeneratedRequest in arguments dictionary\n"); + plist_free(request); + return NULL; + } + plist_dict_merge(&request, device_generated_request); + + info("Sending %s TSS request...\n", s_updater_name); + response = tss_request_send(request, client->tss_url); + plist_free(request); + if (response == NULL) { + error("ERROR: Unable to fetch %s ticket\n", s_updater_name); + return NULL; + } + + if (plist_dict_get_item(response, response_ticket)) { + info("Received %s\n", response_ticket); + } else { + error("ERROR: No '%s' in TSS response, this might not work\n", response_ticket); + debug_plist(response); + } + + return response; +} + static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) { char *comp_name = "Baobab,TCON"; @@ -3072,6 +3127,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, "PS190") == 0) { + fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get PCON1 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) { @@ -3085,8 +3146,12 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct goto error_out; } } else { - error("ERROR: %s: Got unknown updater name '%s'.\n", __func__, s_updater_name); - goto error_out; + error("ERROR: %s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); + fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); + goto error_out; + } } free(s_updater_name); s_updater_name = NULL; From 9b9bba770bda29a09908a287c6f8b9bf15ae9a08 Mon Sep 17 00:00:00 2001 From: Daniel VanBritsom Date: Wed, 6 Sep 2023 12:38:17 +0200 Subject: [PATCH 031/117] tss: Bump auth client version to match iOS 16.5 Sourced from the iOS 16.5 UpdateBrain.dylib --- src/tss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tss.c b/src/tss.c index 9fb74af3..b8af70fe 100644 --- a/src/tss.c +++ b/src/tss.c @@ -35,7 +35,7 @@ #include "endianness.h" -#define AUTH_VERSION "850.0.2" +#define AUTH_VERSION "914.120.2" #ifdef WIN32 #define TSS_CLIENT_VERSION_STRING "libauthinstall_Win-"AUTH_VERSION"" From c8b9f3e582d3543391f7db4cafe96051484f60a9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 6 Sep 2023 17:03:02 +0200 Subject: [PATCH 032/117] fdr: Fix a debug log message --- src/fdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fdr.c b/src/fdr.c index e3703fe8..ca9b7c75 100644 --- a/src/fdr.c +++ b/src/fdr.c @@ -575,7 +575,7 @@ static int fdr_handle_proxy_cmd(fdr_client_t fdr) break; } if (bytes) { - debug("FDR %p got payload of %u bytes, now try to proxy it\n", fdr, bytes); + debug("FDR %p got payload of %u bytes, now trying to proxy it\n", fdr, bytes); debug("Sending %u bytes of data\n", bytes); sent = 0; while (sent < bytes) { From 4191036d58175a873c464d966d8c9e0aa1ec3494 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 13 Sep 2023 13:42:48 +0200 Subject: [PATCH 033/117] restore: Remove plist debug print for non-existent UniqueBuildID and print it in a better format if it does exist --- src/restore.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 0699be7a..a7072f0a 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3373,7 +3373,10 @@ plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8 variant, 0); plist_t unique_id_node = plist_dict_get_item(client->build_manifest, "UniqueBuildID"); - debug_plist(unique_id_node); + if (unique_id_node) { + printf("UniqueBuildID: "); + plist_write_to_stream(unique_id_node, stdout, PLIST_FORMAT_PRINT, PLIST_OPT_NONE); + } return build_identity; } From 7943b63d3884b58169251926de03197bd510afe9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 13 Sep 2023 13:44:24 +0200 Subject: [PATCH 034/117] normal: Don't do unpair before entering recovery mode, remove pairing record afterwards instead --- src/normal.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/normal.c b/src/normal.c index 7f570dab..b7f9f9d7 100644 --- a/src/normal.c +++ b/src/normal.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "common.h" #include "normal.h" @@ -233,12 +234,6 @@ int normal_enter_recovery(struct idevicerestore_client_t* client) return -1; } - /* unpair the device */ - lockdown_error = lockdownd_unpair(lockdown, NULL); - if (lockdown_error != LOCKDOWN_E_SUCCESS) { - error("WARNING: Could not unpair device\n"); - } - lockdown_error = lockdownd_enter_recovery(lockdown); if (lockdown_error == LOCKDOWN_E_SESSION_INACTIVE) { lockdownd_client_free(lockdown); @@ -285,6 +280,9 @@ int normal_enter_recovery(struct idevicerestore_client_t* client) return -1; } + /* remove pair record for given device */ + usbmuxd_delete_pair_record(client->udid); + return 0; } From 5a00bbd88790c2542233906c458473190b41da33 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 14 Sep 2023 00:10:43 +0200 Subject: [PATCH 035/117] tss: Make missing ApNonce non-fatal for IMG3 For IMG3 devices, DFU does not provide ApNonce, but a valid SHSH is needed to boot into iBSS (which then does provide ApNonce). Thanks to @tihmstar for providing the fix! --- src/tss.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tss.c b/src/tss.c index b8af70fe..0fa17408 100644 --- a/src/tss.c +++ b/src/tss.c @@ -316,8 +316,7 @@ int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters) } if (_plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { - error("ERROR: Unable to find required ApNonce in parameters\n"); - return -1; + error("WARNING: Unable to find ApNonce in parameters\n"); } plist_dict_set_item(request, "@APTicket", plist_new_bool(1)); From 95466549006709bf37a751091ae23e989085810c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 14 Sep 2023 01:41:01 +0200 Subject: [PATCH 036/117] [github-actions] Updated to use checkout@v3 --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6bd25bc5..3606be9b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -57,7 +57,7 @@ jobs: rm -rf extract/lib sudo cp -r extract/* / sudo ldconfig - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - name: autogen @@ -129,7 +129,7 @@ jobs: tar -C extract -xvf $I done sudo cp -r extract/* / - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: install additional requirements run: | SDKDIR=`xcrun --sdk macosx --show-sdk-path 2>/dev/null` @@ -260,7 +260,7 @@ jobs: tar -C extract -xvf $I done cp -r extract/* / - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: install additional requirements run: | FILENAME="libzip-1.7.1-static.tar.bz2" From cc9c68e298cadab4b5dfbb32f36fe71b2daf47e0 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 14 Sep 2023 01:48:51 +0200 Subject: [PATCH 037/117] autoconf: Link against libusbmuxd too --- configure.ac | 3 +++ src/Makefile.am | 2 ++ 2 files changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac index cadd48eb..572e2804 100644 --- a/configure.ac +++ b/configure.ac @@ -17,6 +17,7 @@ fi # Minimum package versions LIBIRECOVERY_VERSION=1.0.1 LIBIMOBILEDEVICE_VERSION=1.3.0 +LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.3.0 LIMD_GLUE_VERSION=1.0.0 LIBZIP_VERSION=1.0 @@ -25,6 +26,7 @@ OPENSSL_VERSION=0.9.8 AC_SUBST(LIBIRECOVERY_VERSION) AC_SUBST(LIBIMOBILEDEVICE_VERSION) +AC_SUBST(LIBUSBMUXD_VERSION) AC_SUBST(LIBPLIST_VERSION) AC_SUBST(LIMD_GLUE_VERSION) AC_SUBST(LIBZIP_VERSION) @@ -39,6 +41,7 @@ LT_INIT # Checks for libraries. PKG_CHECK_MODULES(libirecovery, libirecovery-1.0 >= $LIBIRECOVERY_VERSION) PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= $LIBIMOBILEDEVICE_VERSION) +PKG_CHECK_MODULES(libusbmuxd, libusbmuxd-2.0 >= $LIBUSBMUXD_VERSION) PKG_CHECK_MODULES(libplist, libplist-2.0 >= $LIBPLIST_VERSION) PKG_CHECK_MODULES(limd_glue, libimobiledevice-glue-1.0 >= $LIMD_GLUE_VERSION) PKG_CHECK_MODULES(libzip, libzip >= $LIBZIP_VERSION) diff --git a/src/Makefile.am b/src/Makefile.am index a89a9c66..019424ba 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,6 +3,7 @@ AM_CFLAGS = \ $(LFS_CFLAGS) \ $(libirecovery_CFLAGS) \ $(libimobiledevice_CFLAGS) \ + $(libusbmuxd_CFLAGS) \ $(libplist_CFLAGS) \ $(limd_glue_CFLAGS) \ $(libzip_CFLAGS) \ @@ -14,6 +15,7 @@ AM_LDFLAGS = \ $(AC_LDFLAGS) \ $(libirecovery_LIBS) \ $(libimobiledevice_LIBS) \ + $(libusbmuxd_LIBS) \ $(libplist_LIBS) \ $(limd_glue_LIBS) \ $(libzip_LIBS) \ From 17969ef91403f1a914d43584caf9fa0da89d649e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 14 Sep 2023 01:55:18 +0200 Subject: [PATCH 038/117] [github-actions] Updated to use upload-artifact@v3 --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3606be9b..9a92883b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,7 +72,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf idevicerestore.tar usr - name: publish artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: idevicerestore-latest_${{env.target_triplet}} path: idevicerestore.tar @@ -182,7 +182,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf idevicerestore.tar usr - name: publish artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: idevicerestore-latest_macOS path: idevicerestore.tar @@ -282,7 +282,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf idevicerestore.tar ${{ env.dest }} - name: publish artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: idevicerestore-latest_${{ matrix.arch }}-${{ env.dest }} path: idevicerestore.tar From dbe7313260ddef6b2eb60b3772d1595bfd91f24c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 14 Sep 2023 02:34:06 +0200 Subject: [PATCH 039/117] Refactor ipsw code to transparently stream images directly from ZIP or extracted ipsw This allows flashing directly from IPSW archive without having to extract it first, and ultimately removes the "Extracting filesystem from IPSW" part. Restoring from extracted IPSW is also supported, just pass the path to the directory that has all the files from a given IPSW. --- src/asr.c | 56 +++------ src/asr.h | 9 +- src/common.h | 6 +- src/idevicerestore.c | 195 +++++-------------------------- src/idevicerestore.h | 7 +- src/ipsw.c | 269 +++++++++++++++++++++++++------------------ src/ipsw.h | 43 +++++-- src/restore.c | 35 ++++-- src/restore.h | 7 +- 9 files changed, 272 insertions(+), 355 deletions(-) diff --git a/src/asr.c b/src/asr.c index a1aba768..b2aeaf50 100644 --- a/src/asr.c +++ b/src/asr.c @@ -43,6 +43,7 @@ #include "asr.h" #include "idevicerestore.h" #include "common.h" +#include "ipsw.h" #define ASR_VERSION 1 #define ASR_STREAM_ID 1 @@ -205,9 +206,8 @@ void asr_free(asr_client_t asr) } } -int asr_perform_validation(asr_client_t asr, const char* filesystem) +int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) { - FILE* file = NULL; uint64_t length = 0; char* command = NULL; plist_t node = NULL; @@ -216,20 +216,9 @@ int asr_perform_validation(asr_client_t asr, const char* filesystem) plist_t payload_info = NULL; int attempts = 0; - file = fopen(filesystem, "rb"); - if (file == NULL) { - return -1; - } - -#ifdef WIN32 - length = _lseeki64(fileno(file), 0, SEEK_END); - _lseeki64(fileno(file), 0, SEEK_SET); - rewind(file); -#else - fseeko(file, 0, SEEK_END); - length = ftello(file); - fseeko(file, 0, SEEK_SET); -#endif + ipsw_file_seek(file, 0, SEEK_END); + length = ipsw_file_tell(file); + ipsw_file_seek(file, 0, SEEK_SET); payload_info = plist_new_dict(); plist_dict_set_item(payload_info, "Port", plist_new_uint(1)); @@ -296,7 +285,7 @@ int asr_perform_validation(asr_client_t asr, const char* filesystem) return 0; } -int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file) +int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, ipsw_file_handle_t file) { char* oob_data = NULL; uint64_t oob_offset = 0; @@ -324,13 +313,8 @@ int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file) return -1; } -#ifdef WIN32 - rewind(file); - _lseeki64(fileno(file), oob_offset, SEEK_SET); -#else - fseeko(file, oob_offset, SEEK_SET); -#endif - if (fread(oob_data, 1, oob_length, file) != oob_length) { + ipsw_file_seek(file, oob_offset, SEEK_SET); + if (ipsw_file_read(file, oob_data, oob_length) != oob_length) { error("ERROR: Unable to read OOB data from filesystem offset: %s\n", strerror(errno)); free(oob_data); return -1; @@ -345,28 +329,15 @@ int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file) return 0; } -int asr_send_payload(asr_client_t asr, const char* filesystem) +int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) { char *data = NULL; - FILE* file = NULL; uint64_t i, length, bytes = 0; double progress = 0; - file = fopen(filesystem, "rb"); - if (file == NULL) { - error("ERROR: Unable to open filesystem image %s: %s\n", filesystem, strerror(errno)); - return -1; - } - -#ifdef WIN32 - length = _lseeki64(fileno(file), 0, SEEK_END); - _lseeki64(fileno(file), 0, SEEK_SET); - rewind(file); -#else - fseeko(file, 0, SEEK_END); - length = ftello(file); - fseeko(file, 0, SEEK_SET); -#endif + ipsw_file_seek(file, 0, SEEK_END); + length = ipsw_file_tell(file); + ipsw_file_seek(file, 0, SEEK_SET); data = (char*)malloc(ASR_PAYLOAD_CHUNK_SIZE + 20); @@ -385,7 +356,7 @@ int asr_send_payload(asr_client_t asr, const char* filesystem) size = i; } - if (fread(data, 1, size, file) != (size_t)size) { + if (ipsw_file_read(file, data, size) != (int64_t)size) { error("Error reading filesystem\n"); retry--; continue; @@ -412,6 +383,5 @@ int asr_send_payload(asr_client_t asr, const char* filesystem) } free(data); - fclose(file); return 0; } diff --git a/src/asr.h b/src/asr.h index b3336a57..0d9534c2 100644 --- a/src/asr.h +++ b/src/asr.h @@ -41,15 +41,18 @@ struct asr_client { }; typedef struct asr_client *asr_client_t; +struct ipsw_file_handle; +typedef struct ipsw_file_handle* ipsw_file_handle_t; + int asr_open_with_timeout(idevice_t device, asr_client_t* asr); void asr_set_progress_callback(asr_client_t asr, asr_progress_cb_t, void* userdata); int asr_send(asr_client_t asr, plist_t data); int asr_receive(asr_client_t asr, plist_t* data); int asr_send_buffer(asr_client_t asr, const char* data, uint32_t size); void asr_free(asr_client_t asr); -int asr_perform_validation(asr_client_t asr, const char* filesystem); -int asr_send_payload(asr_client_t asr, const char* filesystem); -int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, FILE* file); +int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file); +int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file); +int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, ipsw_file_handle_t file); #ifdef __cplusplus diff --git a/src/common.h b/src/common.h index 97d5f964..5afe5abb 100644 --- a/src/common.h +++ b/src/common.h @@ -70,6 +70,9 @@ struct dfu_client_t; struct normal_client_t; struct restore_client_t; struct recovery_client_t; +struct ipsw_archive; + +typedef struct ipsw_archive* ipsw_archive_t; struct idevicerestore_mode_t { int index; @@ -101,8 +104,7 @@ struct idevicerestore_client_t { plist_t preflight_info; char* udid; char* srnm; - char* ipsw; - const char* filesystem; + ipsw_archive_t ipsw; struct dfu_client_t* dfu; struct restore_client_t* restore; struct recovery_client_t* recovery; diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 466cfe2e..7b69a9f0 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -320,6 +320,8 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata) } } +int build_identity_check_components_in_ipsw(plist_t build_identity, ipsw_archive_t ipsw); + int idevicerestore_start(struct idevicerestore_client_t* client) { int tss_enabled = 0; @@ -424,7 +426,9 @@ int idevicerestore_start(struct idevicerestore_client_t* client) download_to_file(s_wtfurl, wtfipsw, 0); } - ipsw_extract_to_memory(wtfipsw, wtfname, &wtftmp, &wtfsize); + ipsw_archive_t wtf_ipsw = ipsw_open(wtfipsw); + ipsw_extract_to_memory(wtf_ipsw, wtfname, &wtftmp, &wtfsize); + ipsw_close(wtf_ipsw); if (!wtftmp) { error("ERROR: Could not extract WTF\n"); } @@ -601,12 +605,16 @@ int idevicerestore_start(struct idevicerestore_client_t* client) char* ipsw = NULL; res = ipsw_download_fw(fwurl, p_fwsha1, client->cache_dir, &ipsw); if (res != 0) { - if (ipsw) { - free(ipsw); - } + free(ipsw); return res; } else { - client->ipsw = ipsw; + client->ipsw = ipsw_open(ipsw); + if (!client->ipsw) { + error("ERROR: Failed to open ipsw '%s'\n", ipsw); + free(ipsw); + return -1; + } + free(ipsw); } } idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.6); @@ -641,23 +649,17 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } - // verify if ipsw file exists - if (access(client->ipsw, F_OK) < 0) { - error("ERROR: Firmware file %s does not exist.\n", client->ipsw); - return -1; - } - // extract buildmanifest if (client->flags & FLAG_CUSTOM) { info("Extracting Restore.plist from IPSW\n"); if (ipsw_extract_restore_plist(client->ipsw, &client->build_manifest) < 0) { - error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw); + error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw->path); return -1; } } else { info("Extracting BuildManifest from IPSW\n"); if (ipsw_extract_build_manifest(client->ipsw, &client->build_manifest, &tss_enabled) < 0) { - error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw); + error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw->path); return -1; } } @@ -941,115 +943,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) /* check if all components we need are actually there */ info("Checking IPSW for required components...\n"); if (build_identity_check_components_in_ipsw(build_identity, client->ipsw) < 0) { - error("ERROR: Could not find all required components in IPSW %s\n", client->ipsw); + error("ERROR: Could not find all required components in IPSW %s\n", client->ipsw->path); return -1; } info("All required components found in IPSW\n"); - // Get filesystem name from build identity - char* fsname = NULL; - if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) { - error("ERROR: Unable to get path for filesystem component\n"); - return -1; - } - - // check if we already have an extracted filesystem - int delete_fs = 0; - char* filesystem = NULL; - struct stat st; - memset(&st, '\0', sizeof(struct stat)); - char tmpf[1024]; - if (client->cache_dir) { - if (stat(client->cache_dir, &st) < 0) { - mkdir_with_parents(client->cache_dir, 0755); - } - strcpy(tmpf, client->cache_dir); - strcat(tmpf, "/"); - char *ipswtmp = strdup(client->ipsw); - strcat(tmpf, basename(ipswtmp)); - free(ipswtmp); - } else { - strcpy(tmpf, client->ipsw); - } - - if (!ipsw_is_directory(client->ipsw)) { - // strip off file extension if given ipsw is not a directory - char* s = tmpf + strlen(tmpf) - 1; - char* p = s; - while (*p != '\0' && *p != '.' && *p != '/' && *p != '\\') p--; - if (s - p < 6) { - if (*p == '.') { - *p = '\0'; - } - } - } - - if (stat(tmpf, &st) < 0) { - __mkdir(tmpf, 0755); - } - strcat(tmpf, "/"); - strcat(tmpf, fsname); - - memset(&st, '\0', sizeof(struct stat)); - if (stat(tmpf, &st) == 0) { - uint64_t fssize = 0; - ipsw_get_file_size(client->ipsw, fsname, &fssize); - if ((fssize > 0) && ((uint64_t)st.st_size == fssize)) { - info("Using cached filesystem from '%s'\n", tmpf); - filesystem = strdup(tmpf); - } - } - - if (!filesystem && !(client->flags & FLAG_SHSHONLY)) { - char extfn[1024]; - strcpy(extfn, tmpf); - strcat(extfn, ".extract"); - char lockfn[1024]; - strcpy(lockfn, tmpf); - strcat(lockfn, ".lock"); - lock_info_t li; - - lock_file(lockfn, &li); - FILE* extf = NULL; - if (access(extfn, F_OK) != 0) { - extf = fopen(extfn, "wb"); - } - unlock_file(&li); - if (!extf) { - // use temp filename - filesystem = get_temp_filename("ipsw_"); - if (!filesystem) { - error("WARNING: Could not get temporary filename, using '%s' in current directory\n", fsname); - filesystem = strdup(fsname); - } - delete_fs = 1; - } else { - // use .extract as filename - filesystem = strdup(extfn); - fclose(extf); - } - remove(lockfn); - - // Extract filesystem from IPSW - info("Extracting filesystem from IPSW: %s\n", fsname); - if (ipsw_extract_to_file_with_progress(client->ipsw, fsname, filesystem, 1) < 0) { - error("ERROR: Unable to extract filesystem from IPSW\n"); - if (client->tss) - plist_free(client->tss); - info("Removing %s\n", filesystem); - unlink(filesystem); - return -1; - } - - if (strstr(filesystem, ".extract")) { - // rename .extract to - remove(tmpf); - rename(filesystem, tmpf); - free(filesystem); - filesystem = strdup(tmpf); - } - } - idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.2); /* retrieve shsh blobs if required */ @@ -1140,8 +1038,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } if (client->flags & FLAG_SHSHONLY) { @@ -1196,8 +1092,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.25); if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } @@ -1214,8 +1108,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.3); if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } @@ -1226,16 +1118,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if ((client->flags & FLAG_CUSTOM) && limera1n_is_supported(client->device)) { info("connecting to DFU\n"); if (dfu_client_new(client) < 0) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } info("exploiting with limera1n\n"); if (limera1n_exploit(client->device, &client->dfu->client) != 0) { error("ERROR: limera1n exploit failed\n"); dfu_client_free(client); - if (delete_fs && filesystem) - unlink(filesystem); return -1; } dfu_client_free(client); @@ -1245,8 +1133,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) error("ERROR: Unable to place device into recovery mode from DFU mode\n"); if (client->tss) plist_free(client->tss); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } } else if (client->mode == MODE_RECOVERY) { @@ -1256,8 +1142,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) /* send ApTicket */ if (recovery_send_ticket(client) < 0) { error("ERROR: Unable to send APTicket\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } } @@ -1269,8 +1153,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (recovery_send_ibec(client, build_identity) < 0) { mutex_unlock(&client->device_event_mutex); error("ERROR: Unable to send iBEC\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } recovery_client_free(client); @@ -1283,8 +1165,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (!(client->flags & FLAG_QUIT)) { error("ERROR: Device did not disconnect. Possibly invalid iBEC. Reset device and try again.\n"); } - if (delete_fs && filesystem) - unlink(filesystem); return -2; } debug("Waiting for device to reconnect in recovery mode...\n"); @@ -1294,16 +1174,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (!(client->flags & FLAG_QUIT)) { error("ERROR: Device did not reconnect in recovery mode. Possibly invalid iBEC. Reset device and try again.\n"); } - if (delete_fs && filesystem) - unlink(filesystem); return -2; } mutex_unlock(&client->device_event_mutex); } idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.5); if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } @@ -1315,8 +1191,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (get_ap_nonce(client, &nonce, &nonce_size) < 0) { error("ERROR: Unable to get nonce from device!\n"); recovery_send_reset(client); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } @@ -1336,14 +1210,10 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_free(client->tss); if (get_tss_response(client, build_identity, &client->tss) < 0) { error("ERROR: Unable to get SHSH blobs for this device\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -1; } if (!client->tss) { error("ERROR: can't continue without TSS\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -1; } fixup_tss(client->tss); @@ -1351,8 +1221,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.7); if (client->flags & FLAG_QUIT) { - if (delete_fs && filesystem) - unlink(filesystem); return -1; } @@ -1362,8 +1230,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) error("ERROR: Unable to place device into restore mode\n"); if (client->tss) plist_free(client->tss); - if (delete_fs && filesystem) - unlink(filesystem); return -2; } recovery_client_free(client); @@ -1378,8 +1244,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) mutex_unlock(&client->device_event_mutex); error("ERROR: Device failed to enter restore mode.\n"); error("Please make sure that usbmuxd is running.\n"); - if (delete_fs && filesystem) - unlink(filesystem); return -1; } mutex_unlock(&client->device_event_mutex); @@ -1393,19 +1257,13 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } client->ignore_device_add_events = 1; info("About to restore device... \n"); - result = restore_device(client, build_identity, filesystem); + result = restore_device(client, build_identity); if (result < 0) { error("ERROR: Unable to restore device\n"); - if (delete_fs && filesystem) - unlink(filesystem); return result; } } - info("Cleaning up...\n"); - if (delete_fs && filesystem) - unlink(filesystem); - /* special handling of older AppleTVs as they enter Recovery mode on boot when plugged in to USB */ if ((strncmp(client->device->product_type, "AppleTV", 7) == 0) && (client->device->product_type[7] < '5')) { if (recovery_client_new(client) == 0) { @@ -1476,7 +1334,7 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client) free(client->srnm); } if (client->ipsw) { - free(client->ipsw); + ipsw_close(client->ipsw); } if (client->version) { free(client->version); @@ -1535,11 +1393,11 @@ void idevicerestore_set_ipsw(struct idevicerestore_client_t* client, const char* if (!client) return; if (client->ipsw) { - free(client->ipsw); + ipsw_close(client->ipsw); client->ipsw = NULL; } if (path) { - client->ipsw = strdup(path); + client->ipsw = ipsw_open(path); } } @@ -1795,7 +1653,12 @@ int main(int argc, char* argv[]) { info("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); if (ipsw) { - client->ipsw = strdup(ipsw); + // verify if ipsw file exists + client->ipsw = ipsw_open(ipsw); + if (!client->ipsw) { + error("ERROR: Firmware file %s cannot be opened.\n", ipsw); + return -1; + } } curl_global_init(CURL_GLOBAL_ALL); @@ -2570,7 +2433,7 @@ int build_manifest_get_identity_count(plist_t build_manifest) return plist_array_get_size(build_identities_array); } -int extract_component(const char* ipsw, const char* path, unsigned char** component_data, unsigned int* component_size) +int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** component_data, unsigned int* component_size) { char* component_name = NULL; if (!ipsw || !path || !component_data || !component_size) { @@ -2585,7 +2448,7 @@ int extract_component(const char* ipsw, const char* path, unsigned char** compon info("Extracting %s (%s)...\n", component_name, path); if (ipsw_extract_to_memory(ipsw, path, component_data, component_size) < 0) { - error("ERROR: Unable to extract %s from %s\n", component_name, ipsw); + error("ERROR: Unable to extract %s from %s\n", component_name, ipsw->path); return -1; } @@ -2718,7 +2581,7 @@ void build_identity_print_information(plist_t build_identity) node = NULL; } -int build_identity_check_components_in_ipsw(plist_t build_identity, const char *ipsw) +int build_identity_check_components_in_ipsw(plist_t build_identity, ipsw_archive_t ipsw) { plist_t manifest_node = plist_dict_get_item(build_identity, "Manifest"); if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 8a5736ff..880562ff 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -52,6 +52,8 @@ extern "C" { #define RESTORE_VARIANT_MACOS_RECOVERY_OS "macOS Customer" struct idevicerestore_client_t; +struct ipsw_archive; +typedef struct ipsw_archive* ipsw_archive_t; enum { RESTORE_STEP_DETECT = 0, @@ -108,11 +110,10 @@ plist_t build_manifest_get_build_identity_for_model(plist_t build_manifest, cons plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_manifest, const char *hardware_model, const char *variant, int exact); int build_manifest_get_build_count(plist_t build_manifest); void build_identity_print_information(plist_t build_identity); -int build_identity_check_components_in_ipsw(plist_t build_identity, const char* ipsw); int build_identity_has_component(plist_t build_identity, const char* component); int build_identity_get_component_path(plist_t build_identity, const char* component, char** path); -int ipsw_extract_filesystem(const char* ipsw, plist_t build_identity, char** filesystem); -int extract_component(const char* ipsw, const char* path, unsigned char** component_data, unsigned int* component_size); +int ipsw_extract_filesystem(ipsw_archive_t ipsw, plist_t build_identity, char** filesystem); +int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** component_data, unsigned int* component_size); int personalize_component(const char *component, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size); int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* manifest); diff --git a/src/ipsw.c b/src/ipsw.c index fafe5830..58d817c6 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -55,16 +55,8 @@ #define BUFSIZE 0x100000 -typedef struct { - struct zip* zip; - char *path; -} ipsw_archive; - static int cancel_flag = 0; -ipsw_archive* ipsw_open(const char* ipsw); -void ipsw_close(ipsw_archive* archive); - static char* build_path(const char* path, const char* file) { size_t plen = strlen(path); @@ -118,11 +110,14 @@ int ipsw_print_info(const char* path) uint32_t plist_len = 0; if (memcmp(&magic, "PK\x03\x04", 4) == 0) { + ipsw_archive_t ipsw = ipsw_open(thepath); unsigned int rlen = 0; - if (ipsw_extract_to_memory(thepath, "BuildManifest.plist", (unsigned char**)&plist_buf, &rlen) < 0) { + if (ipsw_extract_to_memory(ipsw, "BuildManifest.plist", (unsigned char**)&plist_buf, &rlen) < 0) { + ipsw_close(ipsw); error("ERROR: Failed to extract BuildManifest.plist from IPSW!\n"); return -1; } + ipsw_close(ipsw); plist_len = (uint32_t)rlen; } else { size_t rlen = 0; @@ -310,10 +305,10 @@ int ipsw_print_info(const char* path) return 0; } -ipsw_archive* ipsw_open(const char* ipsw) +ipsw_archive_t ipsw_open(const char* ipsw) { int err = 0; - ipsw_archive* archive = (ipsw_archive*) malloc(sizeof(ipsw_archive)); + ipsw_archive_t archive = (ipsw_archive_t)malloc(sizeof(struct ipsw_archive)); if (archive == NULL) { error("ERROR: Out of memory\n"); return NULL; @@ -324,7 +319,6 @@ ipsw_archive* ipsw_open(const char* ipsw) error("ERROR: ipsw_open %s: %s\n", ipsw, strerror(errno)); return NULL; } - archive->path = strdup(ipsw); if (S_ISDIR(fst.st_mode)) { archive->zip = NULL; } else { @@ -335,7 +329,20 @@ ipsw_archive* ipsw_open(const char* ipsw) return NULL; } } - return archive; + archive->path = strdup(ipsw); + return (ipsw_archive_t)archive; +} + +void ipsw_close(ipsw_archive_t ipsw) +{ + if (ipsw != NULL) { + free(ipsw->path); + if (ipsw->zip) { + zip_unchange_all(ipsw->zip); + zip_close(ipsw->zip); + } + free(ipsw); + } } int ipsw_is_directory(const char* ipsw) @@ -348,37 +355,33 @@ int ipsw_is_directory(const char* ipsw) return S_ISDIR(fst.st_mode); } -int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size) +int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size) { - ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL) { + if (ipsw == NULL) { error("ERROR: Invalid archive\n"); return -1; } - if (archive->zip) { - int zindex = zip_name_locate(archive->zip, infile, 0); + if (ipsw->zip) { + int zindex = zip_name_locate(ipsw->zip, infile, 0); if (zindex < 0) { error("ERROR: zip_name_locate: %s\n", infile); - ipsw_close(archive); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { error("ERROR: zip_stat_index: %s\n", infile); - ipsw_close(archive); return -1; } *size = zstat.size; } else { - char *filepath = build_path(archive->path, infile); + char *filepath = build_path(ipsw->path, infile); struct stat fst; if (stat(filepath, &fst) != 0) { free(filepath); - ipsw_close(archive); return -1; } free(filepath); @@ -386,30 +389,22 @@ int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size) *size = fst.st_size; } - ipsw_close(archive); return 0; } -int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, const char* outfile, int print_progress) +int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, const char* outfile, int print_progress) { int ret = 0; - ipsw_archive* archive = NULL; if (!ipsw || !infile || !outfile) { error("ERROR: Invalid argument\n"); return -1; } - archive = ipsw_open(ipsw); - if (archive == NULL) { - error("ERROR: Invalid archive\n"); - return -1; - } - cancel_flag = 0; - if (archive->zip) { - int zindex = zip_name_locate(archive->zip, infile, 0); + if (ipsw->zip) { + int zindex = zip_name_locate(ipsw->zip, infile, 0); if (zindex < 0) { error("ERROR: zip_name_locate: %s\n", infile); return -1; @@ -417,7 +412,7 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { error("ERROR: zip_stat_index: %s\n", infile); return -1; } @@ -428,7 +423,7 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con return -1; } - struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); + struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0); if (zfile == NULL) { error("ERROR: zip_fopen_index: %s\n", infile); return -1; @@ -472,7 +467,7 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con fclose(fd); zip_fclose(zfile); } else { - char *filepath = build_path(archive->path, infile); + char *filepath = build_path(ipsw->path, infile); char actual_filepath[PATH_MAX+1]; char actual_outfile[PATH_MAX+1]; if (!filepath) { @@ -553,76 +548,66 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con leave: free(filepath); } - ipsw_close(archive); if (cancel_flag) { ret = -2; } return ret; } -int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfile) +int ipsw_extract_to_file(ipsw_archive_t ipsw, const char* infile, const char* outfile) { return ipsw_extract_to_file_with_progress(ipsw, infile, outfile, 0); } -int ipsw_file_exists(const char* ipsw, const char* infile) +int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile) { - ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL) { + if (!ipsw) { return 0; } - if (archive->zip) { - int zindex = zip_name_locate(archive->zip, infile, 0); + if (ipsw->zip) { + int zindex = zip_name_locate(ipsw->zip, infile, 0); if (zindex < 0) { - ipsw_close(archive); return 0; } } else { - char *filepath = build_path(archive->path, infile); + char *filepath = build_path(ipsw->path, infile); if (access(filepath, R_OK) != 0) { free(filepath); - ipsw_close(archive); return 0; } free(filepath); } - ipsw_close(archive); - return 1; } -int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize) +int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize) { size_t size = 0; unsigned char* buffer = NULL; - ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL) { + if (ipsw == NULL) { error("ERROR: Invalid archive\n"); return -1; } - if (archive->zip) { - int zindex = zip_name_locate(archive->zip, infile, 0); + if (ipsw->zip) { + int zindex = zip_name_locate(ipsw->zip, infile, 0); if (zindex < 0) { debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); - ipsw_close(archive); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { error("ERROR: zip_stat_index: %s\n", infile); - ipsw_close(archive); return -1; } - struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); + struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0); if (zfile == NULL) { error("ERROR: zip_fopen_index: %s\n", infile); - ipsw_close(archive); return -1; } @@ -631,7 +616,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** if (buffer == NULL) { error("ERROR: Out of memory\n"); zip_fclose(zfile); - ipsw_close(archive); return -1; } @@ -639,7 +623,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** error("ERROR: zip_fread: %s\n", infile); zip_fclose(zfile); free(buffer); - ipsw_close(archive); return -1; } @@ -647,7 +630,7 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** zip_fclose(zfile); } else { - char *filepath = build_path(archive->path, infile); + char *filepath = build_path(ipsw->path, infile); struct stat fst; #ifdef WIN32 if (stat(filepath, &fst) != 0) { @@ -656,7 +639,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** #endif error("ERROR: %s: stat failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); - ipsw_close(archive); return -1; } size = fst.st_size; @@ -664,7 +646,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** if (buffer == NULL) { error("ERROR: Out of memory\n"); free(filepath); - ipsw_close(archive); return -1; } @@ -674,7 +655,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** error("ERROR: %s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); - ipsw_close(archive); return -1; } } else { @@ -684,7 +664,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** error("ERROR: %s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); - ipsw_close(archive); return -2; } if (fread(buffer, 1, size, f) != size) { @@ -692,7 +671,6 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** error("ERROR: %s: fread failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); - ipsw_close(archive); return -1; } fclose(f); @@ -703,45 +681,40 @@ int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** free(filepath); } - ipsw_close(archive); *pbuffer = buffer; *psize = size; return 0; } -int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx) +int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx) { unsigned char* buffer = NULL; size_t done = 0; size_t total_size = 0; - ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL) { + if (ipsw == NULL) { error("ERROR: Invalid archive\n"); return -1; } - if (archive->zip) { - int zindex = zip_name_locate(archive->zip, infile, 0); + if (ipsw->zip) { + int zindex = zip_name_locate(ipsw->zip, infile, 0); if (zindex < 0) { debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); - ipsw_close(archive); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(archive->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { error("ERROR: zip_stat_index: %s\n", infile); - ipsw_close(archive); return -1; } - struct zip_file* zfile = zip_fopen_index(archive->zip, zindex, 0); + struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0); if (zfile == NULL) { error("ERROR: zip_fopen_index: %s\n", infile); - ipsw_close(archive); return -1; } @@ -750,7 +723,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ if (buffer == NULL) { error("ERROR: Out of memory\n"); zip_fclose(zfile); - ipsw_close(archive); return -1; } @@ -771,10 +743,9 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ } done += zr; } - zip_fclose(zfile); free(buffer); } else { - char *filepath = build_path(archive->path, infile); + char *filepath = build_path(ipsw->path, infile); struct stat fst; #ifdef WIN32 if (stat(filepath, &fst) != 0) { @@ -783,7 +754,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ #endif error("ERROR: %s: stat failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); - ipsw_close(archive); return -1; } total_size = fst.st_size; @@ -791,7 +761,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ if (buffer == NULL) { error("ERROR: Out of memory\n"); free(filepath); - ipsw_close(archive); return -1; } @@ -802,7 +771,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ error("ERROR: %s: readlink failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); - ipsw_close(archive); return -1; } send_callback(ctx, buffer, (size_t)rl); @@ -813,7 +781,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ error("ERROR: %s: fopen failed for %s: %s\n", __func__, filepath, strerror(errno)); free(filepath); free(buffer); - ipsw_close(archive); return -2; } @@ -838,7 +805,6 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ free(filepath); free(buffer); } - ipsw_close(archive); if (done < total_size) { error("ERROR: %s: Sending file data for %s failed (sent %" PRIu64 "/%" PRIu64 ")\n", __func__, infile, (uint64_t)done, (uint64_t)total_size); @@ -851,7 +817,7 @@ int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_ return 0; } -int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled) +int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int *tss_enabled) { unsigned int size = 0; unsigned char* data = NULL; @@ -881,7 +847,7 @@ int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *t return -1; } -int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist) +int ipsw_extract_restore_plist(ipsw_archive_t ipsw, plist_t* restore_plist) { unsigned int size = 0; unsigned char* data = NULL; @@ -895,10 +861,10 @@ int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist) return -1; } -static int ipsw_list_contents_recurse(ipsw_archive *archive, const char *path, ipsw_list_cb cb, void *ctx) +static int ipsw_list_contents_recurse(ipsw_archive_t ipsw, const char *path, ipsw_list_cb cb, void *ctx) { int ret = 0; - char *base = build_path(archive->path, path); + char *base = build_path(ipsw->path, path); DIR *dirp = opendir(base); @@ -936,10 +902,10 @@ static int ipsw_list_contents_recurse(ipsw_archive *archive, const char *path, i break; } - ret = cb(ctx, archive->path, subpath, &st); + ret = cb(ctx, ipsw, subpath, &st); if (ret >= 0 && S_ISDIR(st.st_mode)) - ipsw_list_contents_recurse(archive, subpath, cb, ctx); + ipsw_list_contents_recurse(ipsw, subpath, cb, ctx); free(fpath); free(subpath); @@ -950,21 +916,19 @@ static int ipsw_list_contents_recurse(ipsw_archive *archive, const char *path, i return ret; } -int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx) +int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx) { int ret = 0; - ipsw_archive* archive = ipsw_open(ipsw); - if (archive == NULL) { - error("ERROR: Invalid archive\n"); + if (ipsw == NULL) { + error("ERROR: Invalid IPSW archive\n"); return -1; } - if (archive->zip) { - int64_t entries = zip_get_num_entries(archive->zip, 0); + if (ipsw->zip) { + int64_t entries = zip_get_num_entries(ipsw->zip, 0); if (entries < 0) { error("ERROR: zip_get_num_entries failed\n"); - ipsw_close(archive); return -1; } @@ -972,7 +936,7 @@ int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx) zip_stat_t stat; zip_stat_init(&stat); - if (zip_stat_index(archive->zip, index, 0, &stat) < 0) { + if (zip_stat_index(ipsw->zip, index, 0, &stat) < 0) { error("ERROR: zip_stat_index failed for %s\n", stat.name); ret = -1; continue; @@ -980,7 +944,7 @@ int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx) uint8_t opsys; uint32_t attributes; - if (zip_file_get_external_attributes(archive->zip, index, 0, &opsys, &attributes) < 0) { + if (zip_file_get_external_attributes(ipsw->zip, index, 0, &opsys, &attributes) < 0) { error("ERROR: zip_file_get_external_attributes failed for %s\n", stat.name); ret = -1; continue; @@ -1010,25 +974,12 @@ int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx) break; } } else { - ret = ipsw_list_contents_recurse(archive, "", cb, ctx); + ret = ipsw_list_contents_recurse(ipsw, "", cb, ctx); } - ipsw_close(archive); return ret; } -void ipsw_close(ipsw_archive* archive) -{ - if (archive != NULL) { - free(archive->path); - if (archive->zip) { - zip_unchange_all(archive->zip); - zip_close(archive->zip); - } - free(archive); - } -} - int ipsw_get_signed_firmwares(const char* product, plist_t* firmwares) { char url[256]; @@ -1352,3 +1303,91 @@ void ipsw_cancel(void) { cancel_flag++; } + +ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path) +{ + ipsw_file_handle_t handle = (ipsw_file_handle_t)calloc(1, sizeof(struct ipsw_file_handle)); + if (ipsw->zip) { + int zindex = zip_name_locate(ipsw->zip, path, 0); + if (zindex < 0) { + error("ERROR: zip_name_locate: %s not found\n", path); + free(handle); + return NULL; + } + handle->zfile = zip_fopen_index(ipsw->zip, zindex, 0); + if (handle->zfile == NULL) { + error("ERROR: zip_fopen_index: %s could not be opened\n", path); + free(handle); + return NULL; + } + + } else { + char *filepath = build_path(ipsw->path, path); + handle->file = fopen(filepath, "rb"); + free(filepath); + if (!handle->file) { + error("ERROR: fopen: %s could not be opened\n", path); + free(handle); + return NULL; + } + } + return handle; +} + +void ipsw_file_close(ipsw_file_handle_t handle) +{ + if (handle && handle->zfile) { + zip_fclose(handle->zfile); + } else if (handle && handle->file) { + fclose(handle->file); + } + free(handle); +} + +int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size) +{ + if (handle && handle->zfile) { + zip_int64_t zr = zip_fread(handle->zfile, buffer, size); + return (int64_t)zr; + } else if (handle && handle->file) { + return fread(buffer, 1, size, handle->file); + } else { + error("ERROR: %s: Invalid file handle\n", __func__); + return -1; + } +} + +int ipsw_file_seek(ipsw_file_handle_t handle, int64_t offset, int whence) +{ + if (handle && handle->zfile) { + return zip_fseek(handle->zfile, offset, whence); + } else if (handle && handle->file) { +#ifdef WIN32 + if (whence == SEEK_SET) { + rewind(handle->file); + } + return (_lseeki64(fileno(handle->file), offset, whence) < 0) ? -1 : 0; +#else + return fseeko(handle->file, offset, whence); +#endif + } else { + error("ERROR: %s: Invalid file handle\n", __func__); + return -1; + } +} + +int64_t ipsw_file_tell(ipsw_file_handle_t handle) +{ + if (handle && handle->zfile) { + return zip_ftell(handle->zfile); + } else if (handle && handle->file) { +#ifdef WIN32 + return _lseeki64(fileno(handle->file), 0, SEEK_CUR); +#else + return ftello(handle->file); +#endif + } else { + error("ERROR: %s: Invalid file handle\n", __func__); + return -1; + } +} diff --git a/src/ipsw.h b/src/ipsw.h index 84ea7a9d..96bcb626 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -32,21 +32,44 @@ extern "C" { #include #include +struct ipsw_archive { + struct zip* zip; + char *path; +}; +typedef struct ipsw_archive* ipsw_archive_t; + +ipsw_archive_t ipsw_open(const char* ipsw); +void ipsw_close(ipsw_archive_t ipsw); + int ipsw_print_info(const char* ipsw); -typedef int (*ipsw_list_cb)(void *ctx, const char* ipsw, const char *name, struct stat *stat); +typedef int (*ipsw_list_cb)(void *ctx, ipsw_archive_t ipsw, const char *name, struct stat *stat); typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size); +struct ipsw_file_handle { + FILE* file; + struct zip_file* zfile; +}; +typedef struct ipsw_file_handle* ipsw_file_handle_t; + +ipsw_file_handle_t ipsw_file_open(ipsw_archive_t, const char* path); +void ipsw_file_close(ipsw_file_handle_t handle); + +int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size); +int ipsw_file_seek(ipsw_file_handle_t handle, int64_t offset, int whence); +int64_t ipsw_file_tell(ipsw_file_handle_t handle); + int ipsw_is_directory(const char* ipsw); -int ipsw_file_exists(const char* ipsw, const char* infile); -int ipsw_get_file_size(const char* ipsw, const char* infile, uint64_t* size); -int ipsw_extract_to_file(const char* ipsw, const char* infile, const char* outfile); -int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, const char* outfile, int print_progress); -int ipsw_extract_to_memory(const char* ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize); -int ipsw_extract_send(const char* ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx); -int ipsw_extract_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled); -int ipsw_extract_restore_plist(const char* ipsw, plist_t* restore_plist); -int ipsw_list_contents(const char* ipsw, ipsw_list_cb cb, void *ctx); + +int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile); +int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size); +int ipsw_extract_to_file(ipsw_archive_t ipsw, const char* infile, const char* outfile); +int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, const char* outfile, int print_progress); +int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned char** pbuffer, unsigned int* psize); +int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ipsw_send_cb send_callback, void* ctx); +int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int *tss_enabled); +int ipsw_extract_restore_plist(ipsw_archive_t ipsw, plist_t* restore_plist); +int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx); int ipsw_get_signed_firmwares(const char* product, plist_t* firmwares); int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir, char** ipswfile); diff --git a/src/restore.c b/src/restore.c index a7072f0a..c1dd92d7 100644 --- a/src/restore.c +++ b/src/restore.c @@ -896,13 +896,26 @@ static void restore_asr_progress_cb(double progress, void* userdata) } } -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, const char* filesystem) +int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, plist_t build_identity) { asr_client_t asr = NULL; info("About to send filesystem...\n"); + ipsw_file_handle_t file = NULL; + char* fsname = NULL; + if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) { + error("ERROR: Unable to get path for filesystem component\n"); + return -1; + } + file = ipsw_file_open(client->ipsw, fsname); + if (!file) { + error("ERROR: Unable to open '%s' in ipsw\n", fsname); + free(fsname); + } + if (asr_open_with_timeout(device, &asr) < 0) { + ipsw_file_close(file); error("ERROR: Unable to connect to ASR\n"); return -1; } @@ -913,7 +926,8 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de // this step sends requested chunks of data from various offsets to asr so // it can validate the filesystem before installing it info("Validating the filesystem\n"); - if (asr_perform_validation(asr, filesystem) < 0) { + if (asr_perform_validation(asr, file) < 0) { + ipsw_file_close(file); error("ERROR: ASR was unable to validate the filesystem\n"); asr_free(asr); return -1; @@ -923,11 +937,14 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de // once the target filesystem has been validated, ASR then requests the // entire filesystem to be sent. info("Sending filesystem now...\n"); - if (asr_send_payload(asr, filesystem) < 0) { + if (asr_send_payload(asr, file) < 0) { + ipsw_file_close(file); error("ERROR: Unable to send payload to ASR\n"); asr_free(asr); return -1; } + ipsw_file_close(file); + info("Done sending filesystem\n"); asr_free(asr); @@ -3275,7 +3292,7 @@ static int cpio_send_file(idevice_connection_t connection, const char *name, str return 0; } -static int restore_bootability_send_one(void *ctx, const char *ipsw, const char *name, struct stat *stat) +static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const char *name, struct stat *stat) { idevice_connection_t connection = (idevice_connection_t)ctx; const char *prefix = "BootabilityBundle/Restore/Bootability/"; @@ -3747,7 +3764,7 @@ int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_ return 0; } -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity, const char* filesystem) +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity) { plist_t node = NULL; @@ -3759,7 +3776,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem if (!strcmp(type, "SystemImageData")) { - if(restore_send_filesystem(client, device, filesystem) < 0) { + if(restore_send_filesystem(client, device, build_identity) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -3795,7 +3812,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem else if (!strcmp(type, "RecoveryOSASRImage")) { - if(restore_send_filesystem(client, device, filesystem) < 0) { + if(restore_send_filesystem(client, device, build_identity) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -4038,7 +4055,7 @@ static void rp_status_cb(reverse_proxy_client_t client, reverse_proxy_status_t s } #endif -int restore_device(struct idevicerestore_client_t* client, plist_t build_identity, const char* filesystem) +int restore_device(struct idevicerestore_client_t* client, plist_t build_identity) { int err = 0; char* type = NULL; @@ -4361,7 +4378,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // files sent to the server by the client. these data requests include // SystemImageData, RootTicket, KernelCache, NORData and BasebandData requests if (!strcmp(type, "DataRequestMsg")) { - err = restore_handle_data_request_msg(client, device, restore, message, build_identity, filesystem); + err = restore_handle_data_request_msg(client, device, restore, message, build_identity); } // restore logs are available if a previous restore failed diff --git a/src/restore.h b/src/restore.h index ad3b7214..765f3746 100644 --- a/src/restore.h +++ b/src/restore.h @@ -38,7 +38,6 @@ struct restore_client_t { idevice_t device; char* udid; unsigned int operation; - const char* filesystem; uint64_t protocol_version; restored_client_t client; }; @@ -52,13 +51,13 @@ int restore_reboot(struct idevicerestore_client_t* client); const char* restore_progress_string(unsigned int operation); int restore_handle_status_msg(restored_client_t client, plist_t msg); int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t msg); -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity, const char* filesystem); +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity); int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message); int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client); int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, const char* component, const char* component_name); -int restore_device(struct idevicerestore_client_t* client, plist_t build_identity, const char* filesystem); +int restore_device(struct idevicerestore_client_t* client, plist_t build_identity); int restore_open_with_timeout(struct idevicerestore_client_t* client); -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, const char* filesystem); +int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, plist_t build_identity); int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device); #ifdef __cplusplus From cf22a1c0fa5994be2f02ed431461524499b06267 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 29 Sep 2023 10:49:25 +0200 Subject: [PATCH 040/117] tss: Add Ap,SikaFuse to TSS request as seen for iPhone 14/15 devices This is currently implemented as a workaround as the evaluation of when this value should be set is unclear. Right now we set it when UID_MODE is set too. --- src/tss.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/tss.c b/src/tss.c index 0fa17408..5fd18045 100644 --- a/src/tss.c +++ b/src/tss.c @@ -305,6 +305,14 @@ int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) plist_dict_set_item(request, "UID_MODE", plist_new_bool(0)); } + // FIXME: I didn't understand yet when this value is set, so for now we use a workaround + if (plist_dict_get_item(parameters, "ApSikaFuse")) { + _plist_dict_copy_item(request, parameters, "Ap,SikaFuse", "ApSikaFuse"); + } else if (_plist_dict_get_bool(parameters, "RequiresUIDMode")) { + // Workaround: We have only seen Ap,SikaFuse together with UID_MODE + plist_dict_set_item(request, "Ap,SikaFuse", plist_new_int(0)); + } + return 0; } From c96f60b8cf4cee0d8a861bf1a924f0f240e04b07 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 2 Oct 2023 15:21:38 +0200 Subject: [PATCH 041/117] restore: Handle SepStage1 (SEPPatchImageData) in NORImageData --- src/restore.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/restore.c b/src/restore.c index c1dd92d7..0fea6e3d 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1396,6 +1396,31 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* personalized_size = 0; } + if (build_identity_has_component(build_identity, "SepStage1") && + build_identity_get_component_path(build_identity, "SepStage1", &sep_path) == 0) { + component = "SepStage1"; + ret = extract_component(client->ipsw, sep_path, &component_data, &component_size); + free(sep_path); + if (ret < 0) { + error("ERROR: Unable to extract component: %s\n", component); + return -1; + } + + ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size); + free(component_data); + component_data = NULL; + component_size = 0; + if (ret < 0) { + error("ERROR: Unable to get personalized component: %s\n", component); + return -1; + } + + plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size)); + free(personalized_data); + personalized_data = NULL; + personalized_size = 0; + } + if (idevicerestore_debug) debug_plist(dict); From ca76f44bdda73cb69e3c67f85718656e96b2d56f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 2 Oct 2023 18:45:55 +0200 Subject: [PATCH 042/117] restore: Attributed status code 50 with SEP load failure --- src/restore.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/restore.c b/src/restore.c index 0fea6e3d..1b246f84 100644 --- a/src/restore.c +++ b/src/restore.c @@ -742,6 +742,7 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) case 27: info("Status: Failed to mount filesystems.\n"); break; + case 50: case 51: info("Status: Failed to load SEP Firmware.\n"); break; From 064daea982e92d425a574b20088f445d2091d582 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 2 Oct 2023 18:59:43 +0200 Subject: [PATCH 043/117] restore: Add new SE,ChipID 0x36 to list of known values --- src/restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 1b246f84..05ff5af8 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2166,7 +2166,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id } if (chip_id == 0x20211) { comp_name = "SE,Firmware"; - } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C) { + } else if (chip_id == 0x73 || chip_id == 0x64 || chip_id == 0xC8 || chip_id == 0xD2 || chip_id == 0x2C || chip_id == 0x36) { comp_name = "SE,UpdatePayload"; } else { info("WARNING: Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id); From e4e551287d15a7d6fc9a0e9e0610e6921e53c0af Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 4 Oct 2023 12:19:01 +0200 Subject: [PATCH 044/117] restore/tss: Prefer DeviceGeneratedRequest for Rose TSS request, and add missing tag --- src/restore.c | 14 ++++++++++---- src/tss.c | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/restore.c b/src/restore.c index 05ff5af8..c6e8a322 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2423,7 +2423,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru return response; } -static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; @@ -2458,8 +2458,14 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0)); } - /* add Rap,* tags from info dictionary to parameters */ - plist_dict_merge(¶meters, p_info); + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request) { + /* use DeviceGeneratedRequest if present */ + plist_dict_merge(&request, device_generated_request); + } else { + /* add Rap,* tags from info dictionary to parameters */ + plist_dict_merge(¶meters, p_info); + } /* add required tags for Rose TSS request */ tss_request_add_rose_tags(request, parameters, NULL); @@ -3153,7 +3159,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct goto error_out; } } else if (strcmp(s_updater_name, "Rose") == 0) { - fwdict = restore_get_rose_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_rose_firmware_data(restore, client, build_identity, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get Rose firmware data\n", __func__); goto error_out; diff --git a/src/tss.c b/src/tss.c index 5fd18045..670cd0a4 100644 --- a/src/tss.c +++ b/src/tss.c @@ -1167,6 +1167,7 @@ int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overr _plist_dict_copy_bool(request, parameters, "Rap,ProductionMode", NULL); _plist_dict_copy_uint(request, parameters, "Rap,SecurityDomain", NULL); _plist_dict_copy_bool(request, parameters, "Rap,SecurityMode", NULL); + _plist_dict_copy_data(request, parameters, "Rap,FdrRootCaDigest", NULL); char *comp_name = NULL; plist_dict_iter iter = NULL; From 1405a9f501e023b7edaa2829c0a2254235332703 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 4 Oct 2023 12:23:21 +0200 Subject: [PATCH 045/117] restore: Refine checkpoint log output --- src/restore.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/restore.c b/src/restore.c index c6e8a322..320d5f06 100644 --- a/src/restore.c +++ b/src/restore.c @@ -4439,29 +4439,38 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit else if (!strcmp(type, "CheckpointMsg")) { uint64_t ckpt_id; - uint64_t ckpt_res; + int64_t ckpt_res; uint8_t ckpt_complete = 0; + const char* ckpt_name = NULL; // Get checkpoint id node = plist_dict_get_item(message, "CHECKPOINT_ID"); - if (!node || plist_get_node_type(node) != PLIST_UINT) { + if (!node || plist_get_node_type(node) != PLIST_INT) { debug("Failed to parse checkpoint id from checkpoint plist\n"); return -1; } plist_get_uint_val(node, &ckpt_id); + // Get checkpoint_name + node = plist_dict_get_item(message, "CHECKPOINT_NAME"); + ckpt_name = (node) ? plist_get_string_ptr(node, NULL) : "unknown"; // Get checkpoint result node = plist_dict_get_item(message, "CHECKPOINT_RESULT"); - if (!node || plist_get_node_type(node) != PLIST_UINT) { + if (!node || plist_get_node_type(node) != PLIST_INT) { debug("Failed to parse checkpoint result from checkpoint plist\n"); return -1; } - plist_get_uint_val(node, &ckpt_res); + plist_get_int_val(node, &ckpt_res); // Get checkpoint complete node = plist_dict_get_item(message, "CHECKPOINT_COMPLETE"); if (PLIST_IS_BOOLEAN(node)) { plist_get_bool_val(node, &ckpt_complete); } - if (ckpt_complete) - info("Checkpoint %" PRIu64 " complete with code %" PRIu64 "\n", ckpt_id, ckpt_res); + + info("Checkpoint %s id: 0x%" PRIX64 " (%s)\n", (ckpt_complete) ? "completed" : "started ", ckpt_id, ckpt_name); + if (ckpt_res != 0) { + node = plist_dict_get_item(message, "CHECKPOINT_ERROR"); + const char* ckpt_error = (node) ? plist_get_string_ptr(node, NULL) : "(unknown)"; + info("Checkpoint FAILED id: 0x%" PRIX64 " error %"PRIi64": %s\n", ckpt_id, ckpt_res, ckpt_error); + } } // baseband update message From 7e5860d249441d0b45e50de2b46475432e3fc908 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 4 Oct 2023 14:39:20 +0200 Subject: [PATCH 046/117] restore: Improve checkpoint log output again, make sure to always check for errors Turns out even with a CHECKPOINT_RESULT of 0 we can still have a CHECKPOINT_ERROR string. --- src/restore.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/restore.c b/src/restore.c index 320d5f06..26a93a02 100644 --- a/src/restore.c +++ b/src/restore.c @@ -4465,11 +4465,14 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit plist_get_bool_val(node, &ckpt_complete); } - info("Checkpoint %s id: 0x%" PRIX64 " (%s)\n", (ckpt_complete) ? "completed" : "started ", ckpt_id, ckpt_name); - if (ckpt_res != 0) { - node = plist_dict_get_item(message, "CHECKPOINT_ERROR"); - const char* ckpt_error = (node) ? plist_get_string_ptr(node, NULL) : "(unknown)"; - info("Checkpoint FAILED id: 0x%" PRIX64 " error %"PRIi64": %s\n", ckpt_id, ckpt_res, ckpt_error); + if (ckpt_complete) { + info("Checkpoint completed id: 0x%" PRIX64 " (%s) result=%" PRIi64 "\n", ckpt_id, ckpt_name, ckpt_res); + } else { + info("Checkpoint started id: 0x%" PRIX64 " (%s)\n", ckpt_id, ckpt_name); + } + node = plist_dict_get_item(message, "CHECKPOINT_ERROR"); + if (node) { + info("Checkpoint FAILURE id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); } } From 523e567f16f45dc3b9a73921d700e026bcc4b94e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 6 Oct 2023 12:12:27 +0200 Subject: [PATCH 047/117] restore: Skip adding FirmwareData to FirmwareResponseData for Rose --- src/restore.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/restore.c b/src/restore.c index 26a93a02..fc7ec9b7 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2487,6 +2487,12 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct error("ERROR: No 'Rap,Ticket' in TSS response, this might not work\n"); } + /* skip FirmwareData for newer versions */ + if (client->build_major >= 20) { + debug("DEBUG: Not adding FirmwareData.\n"); + return response; + } + comp_name = "Rap,RTKitOS"; 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); From f17f5208aa04e71915b9961f76fc6c59c454cd91 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 6 Oct 2023 12:24:55 +0200 Subject: [PATCH 048/117] restore: Add Ace3 as known updater name to suppress error message --- src/restore.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/restore.c b/src/restore.c index fc7ec9b7..1d34a184 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3200,6 +3200,12 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } + } else if (strcmp(s_updater_name, "Ace3") == 0) { + fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + if (fwdict == NULL) { + error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); + goto error_out; + } } else { error("ERROR: %s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); From 6806495ca7df744f635be515c5cdf938ad49ea82 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 6 Oct 2023 20:58:13 +0200 Subject: [PATCH 049/117] restore: Also print checkpoint warning messages --- src/restore.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/restore.c b/src/restore.c index 1d34a184..8063f080 100644 --- a/src/restore.c +++ b/src/restore.c @@ -4482,6 +4482,10 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit } else { info("Checkpoint started id: 0x%" PRIX64 " (%s)\n", ckpt_id, ckpt_name); } + node = plist_dict_get_item(message, "CHECKPOINT_WARNING"); + if (node) { + info("Checkpoint WARNING id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); + } node = plist_dict_get_item(message, "CHECKPOINT_ERROR"); if (node) { info("Checkpoint FAILURE id: 0x%" PRIX64 " result=%" PRIi64 ": %s\n", ckpt_id, ckpt_res, plist_get_string_ptr(node, NULL)); From 503bdd01f5e9f16c583ebff343edee8bfaf3f572 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 7 Oct 2023 02:33:03 +0200 Subject: [PATCH 050/117] Improve debug output by suppressing libimobiledevice and libirecovery debug output by default To get libimobiledevice and libirecovery output, add -d or --debug twice. --- src/common.h | 1 + src/idevicerestore.c | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/common.h b/src/common.h index 5afe5abb..67089434 100644 --- a/src/common.h +++ b/src/common.h @@ -91,6 +91,7 @@ struct idevicerestore_entry_t { struct idevicerestore_client_t { int flags; + int debug_level; plist_t tss; plist_t tss_localpolicy; plist_t tss_recoveryos_root_ticket; diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 7b69a9f0..56207a07 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -341,10 +341,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } - if (client->flags & FLAG_DEBUG) { - idevice_set_debug_level(1); - irecv_set_debug_level(1); + if (client->debug_level > 0) { idevicerestore_debug = 1; + if (client->debug_level > 1) { + idevice_set_debug_level(1); + irecv_set_debug_level(1); + } } idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.0); @@ -1483,6 +1485,7 @@ int main(int argc, char* argv[]) { case 'd': client->flags |= FLAG_DEBUG; + client->debug_level++; break; case 'e': From 4072cd965eab44993700b980d8848b46ec3be72e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 9 Oct 2023 11:32:30 +0200 Subject: [PATCH 051/117] tss: Add USBPortController1,* entries to parameters --- src/tss.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tss.c b/src/tss.c index 670cd0a4..5e676f4b 100644 --- a/src/tss.c +++ b/src/tss.c @@ -245,6 +245,10 @@ int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainVolume", NULL); _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainTrustCache", NULL); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); + node = plist_dict_get_item(build_identity, "Info"); if (node) { _plist_dict_copy_bool(parameters, node, "RequiresUIDMode", NULL); From c871c591e36d2a4083e3dda4c70144a0321ce70f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 2 Nov 2023 12:54:47 +0100 Subject: [PATCH 052/117] Extract OS component when using older ipsw archives Older ipsw archives have the root filesystem stored in compressed format rather than just "stored". The "Verifying Filesystem" step would then fail as compressed files are not seekable in ZIP files. This commit introduces a detection for this and has the filesystem extracted should it be required. If not using a cache path, the temp file used for extraction will be deleted after the procedure is completed. --- src/asr.c | 18 ++++++----- src/common.c | 17 ++++++++++ src/common.h | 4 +++ src/idevicerestore.c | 75 ++++++++++++++++++++++++++++++++++++++++++++ src/ipsw.c | 20 ++++++++++-- src/ipsw.h | 3 ++ src/restore.c | 17 +++++++++- 7 files changed, 143 insertions(+), 11 deletions(-) diff --git a/src/asr.c b/src/asr.c index b2aeaf50..304e8a32 100644 --- a/src/asr.c +++ b/src/asr.c @@ -216,9 +216,7 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) plist_t payload_info = NULL; int attempts = 0; - ipsw_file_seek(file, 0, SEEK_END); - length = ipsw_file_tell(file); - ipsw_file_seek(file, 0, SEEK_SET); + length = ipsw_file_size(file); payload_info = plist_new_dict(); plist_dict_set_item(payload_info, "Port", plist_new_uint(1)); @@ -313,9 +311,14 @@ int asr_handle_oob_data_request(asr_client_t asr, plist_t packet, ipsw_file_hand return -1; } - ipsw_file_seek(file, oob_offset, SEEK_SET); - if (ipsw_file_read(file, oob_data, oob_length) != oob_length) { - error("ERROR: Unable to read OOB data from filesystem offset: %s\n", strerror(errno)); + if (ipsw_file_seek(file, oob_offset, SEEK_SET) < 0) { + error("ERROR: Unable to seek to OOB offset 0x%" PRIx64 "\n", oob_offset); + free(oob_data); + return -1; + } + int64_t ir = ipsw_file_read(file, oob_data, oob_length); + if (ir != oob_length) { + error("ERROR: Unable to read OOB data from filesystem offset 0x%" PRIx64 ", oob_length %" PRIu64 ", read returned %" PRIi64"\n", oob_offset, oob_length, ir); free(oob_data); return -1; } @@ -335,8 +338,7 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) uint64_t i, length, bytes = 0; double progress = 0; - ipsw_file_seek(file, 0, SEEK_END); - length = ipsw_file_tell(file); + length = ipsw_file_size(file); ipsw_file_seek(file, 0, SEEK_SET); data = (char*)malloc(ASR_PAYLOAD_CHUNK_SIZE + 20); diff --git a/src/common.c b/src/common.c index 068f2ddb..0ad775ce 100644 --- a/src/common.c +++ b/src/common.c @@ -695,3 +695,20 @@ int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char * plist_dict_set_item(target_dict, key, plist_copy(node)); return 0; } + +char* path_get_basename(char* path) +{ +#ifdef WIN32 + char *p = path + strlen(path); + while (p > path) { + if ((*p == '/') || (*p == '\\')) { + return p+1; + } + p--; + } + return p; +#else + char *p = strrchr(path, '/'); + return p ? p + 1 : path; +#endif +} diff --git a/src/common.h b/src/common.h index 67089434..c2a96b0a 100644 --- a/src/common.h +++ b/src/common.h @@ -128,6 +128,8 @@ struct idevicerestore_client_t { int ignore_device_add_events; plist_t macos_variant; char* restore_variant; + char* filesystem; + int delete_fs; }; extern struct idevicerestore_mode_t idevicerestore_modes[]; @@ -193,6 +195,8 @@ int _plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char * int _plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); +char* path_get_basename(char* path); + #ifdef __cplusplus } #endif diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 56207a07..dc7750bd 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -45,6 +45,8 @@ #define SHA384 sha384 #endif +#include + #include "dfu.h" #include "tss.h" #include "img3.h" @@ -950,6 +952,73 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } info("All required components found in IPSW\n"); + /* Get OS (filesystem) name from build identity */ + char* os_path = NULL; + if (build_identity_get_component_path(build_identity, "OS", &os_path) < 0) { + error("ERROR: Unable to get path for filesystem component\n"); + return -1; + } + + /* check if IPSW has OS component 'stored' in ZIP archive, otherwise we need to extract it */ + int needs_os_extraction = 0; + if (client->ipsw->zip) { + ipsw_file_handle_t zfile = ipsw_file_open(client->ipsw, os_path); + if (zfile) { + if (!zfile->seekable) { + needs_os_extraction = 1; + } + ipsw_file_close(zfile); + } + } + + if (needs_os_extraction && !(client->flags & FLAG_SHSHONLY)) { + char* tmpf = NULL; + struct stat st; + if (client->cache_dir) { + memset(&st, '\0', sizeof(struct stat)); + if (stat(client->cache_dir, &st) < 0) { + mkdir_with_parents(client->cache_dir, 0755); + } + char* ipsw_basename = path_get_basename(client->ipsw->path); + ipsw_basename = strdup(ipsw_basename); + char* p = strrchr(ipsw_basename, '.'); + if (p && isalpha(*(p+1))) { + *p = '\0'; + } + tmpf = string_build_path(client->cache_dir, ipsw_basename, NULL); + mkdir_with_parents(tmpf, 0755); + free(tmpf); + tmpf = string_build_path(client->cache_dir, ipsw_basename, os_path, NULL); + free(ipsw_basename); + } else { + tmpf = get_temp_filename(NULL); + client->delete_fs = 1; + } + + /* check if we already have it extracted */ + uint64_t fssize = 0; + ipsw_get_file_size(client->ipsw, os_path, &fssize); + memset(&st, '\0', sizeof(struct stat)); + if (stat(tmpf, &st) == 0) { + if ((fssize > 0) && ((uint64_t)st.st_size == fssize)) { + info("Using cached filesystem from '%s'\n", tmpf); + client->filesystem = tmpf; + } + } + + if (!client->filesystem) { + info("Extracting filesystem from IPSW: %s\n", os_path); + if (ipsw_extract_to_file_with_progress(client->ipsw, os_path, tmpf, 1) < 0) { + error("ERROR: Unable to extract filesystem from IPSW\n"); + info("Removing %s\n", tmpf); + unlink(tmpf); + free(tmpf); + return -1; + } + client->filesystem = tmpf; + } + } + idevicerestore_progress(client, RESTORE_STEP_PREPARE, 0.2); /* retrieve shsh blobs if required */ @@ -1338,6 +1407,12 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client) if (client->ipsw) { ipsw_close(client->ipsw); } + if (client->filesystem) { + if (client->delete_fs) { + unlink(client->filesystem); + } + free(client->filesystem); + } if (client->version) { free(client->version); } diff --git a/src/ipsw.c b/src/ipsw.c index 58d817c6..5b1d7323 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -1308,7 +1308,8 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path) { ipsw_file_handle_t handle = (ipsw_file_handle_t)calloc(1, sizeof(struct ipsw_file_handle)); if (ipsw->zip) { - int zindex = zip_name_locate(ipsw->zip, path, 0); + zip_stat_t zst; + zip_int64_t zindex = zip_name_locate(ipsw->zip, path, 0); if (zindex < 0) { error("ERROR: zip_name_locate: %s not found\n", path); free(handle); @@ -1320,8 +1321,12 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path) free(handle); return NULL; } - + zip_stat_init(&zst); + zip_stat(ipsw->zip, path, 0, &zst); + handle->size = zst.size; + handle->seekable = (zst.comp_method == ZIP_CM_STORE); } else { + struct stat st; char *filepath = build_path(ipsw->path, path); handle->file = fopen(filepath, "rb"); free(filepath); @@ -1330,6 +1335,9 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path) free(handle); return NULL; } + fstat(fileno(handle->file), &st); + handle->size = st.st_size; + handle->seekable = 1; } return handle; } @@ -1344,6 +1352,14 @@ void ipsw_file_close(ipsw_file_handle_t handle) free(handle); } +uint64_t ipsw_file_size(ipsw_file_handle_t handle) +{ + if (handle) { + return handle->size; + } + return 0; +} + int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size) { if (handle && handle->zfile) { diff --git a/src/ipsw.h b/src/ipsw.h index 96bcb626..56faf942 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -49,12 +49,15 @@ typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size); struct ipsw_file_handle { FILE* file; struct zip_file* zfile; + uint64_t size; + int seekable; }; typedef struct ipsw_file_handle* ipsw_file_handle_t; ipsw_file_handle_t ipsw_file_open(ipsw_archive_t, const char* path); void ipsw_file_close(ipsw_file_handle_t handle); +uint64_t ipsw_file_size(ipsw_file_handle_t handle); int64_t ipsw_file_read(ipsw_file_handle_t handle, void* buffer, size_t size); int ipsw_file_seek(ipsw_file_handle_t handle, int64_t offset, int whence); int64_t ipsw_file_tell(ipsw_file_handle_t handle); diff --git a/src/restore.c b/src/restore.c index 8063f080..9e0268a2 100644 --- a/src/restore.c +++ b/src/restore.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #ifdef HAVE_REVERSE_PROXY #include @@ -903,13 +904,23 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de info("About to send filesystem...\n"); + ipsw_archive_t ipsw_dummy = NULL; ipsw_file_handle_t file = NULL; char* fsname = NULL; if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) { error("ERROR: Unable to get path for filesystem component\n"); return -1; } - file = ipsw_file_open(client->ipsw, fsname); + if (client->filesystem) { + char* path = strdup(client->filesystem); + char* fsname_base = path_get_basename(path); + char* parent_dir = dirname(path); + ipsw_dummy = ipsw_open(parent_dir); + free(path); + file = ipsw_file_open(ipsw_dummy, fsname_base); + } else { + file = ipsw_file_open(client->ipsw, fsname); + } if (!file) { error("ERROR: Unable to open '%s' in ipsw\n", fsname); free(fsname); @@ -917,6 +928,7 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de if (asr_open_with_timeout(device, &asr) < 0) { ipsw_file_close(file); + ipsw_close(ipsw_dummy); error("ERROR: Unable to connect to ASR\n"); return -1; } @@ -929,6 +941,7 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de info("Validating the filesystem\n"); if (asr_perform_validation(asr, file) < 0) { ipsw_file_close(file); + ipsw_close(ipsw_dummy); error("ERROR: ASR was unable to validate the filesystem\n"); asr_free(asr); return -1; @@ -940,11 +953,13 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de info("Sending filesystem now...\n"); if (asr_send_payload(asr, file) < 0) { ipsw_file_close(file); + ipsw_close(ipsw_dummy); error("ERROR: Unable to send payload to ASR\n"); asr_free(asr); return -1; } ipsw_file_close(file); + ipsw_close(ipsw_dummy); info("Done sending filesystem\n"); From 8664de040b36518c2b1b76edb9cbf9e5a8613965 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 7 Nov 2023 14:45:04 +0100 Subject: [PATCH 053/117] Print device Product and Build Version and IPSW Product and Build Version It wasn't entirely clear what "Product Version" and "Product Build" would be so prefixing it with "IPSW" makes it clear it's the version being restored. --- src/common.h | 2 ++ src/idevicerestore.c | 42 ++++++++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/common.h b/src/common.h index c2a96b0a..f7b1dcd1 100644 --- a/src/common.h +++ b/src/common.h @@ -114,6 +114,8 @@ struct idevicerestore_client_t { struct idevicerestore_mode_t* mode; char* version; char* build; + char* device_version; + char* device_build; int build_major; char* restore_boot_args; char* cache_dir; diff --git a/src/idevicerestore.c b/src/idevicerestore.c index dc7750bd..b2185103 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -478,6 +478,21 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } + if (client->mode == MODE_NORMAL) { + plist_t pver = normal_get_lockdown_value(client, NULL, "ProductVersion"); + if (pver) { + plist_get_string_val(pver, &client->device_version); + plist_free(pver); + } + pver = normal_get_lockdown_value(client, NULL, "BuildVersion"); + if (pver) { + plist_get_string_val(pver, &client->device_build); + plist_free(pver); + } + } + info("Device Product Version: %s\n", (client->device_version) ? client->device_version : "N/A"); + info("Device Product Build: %s\n", (client->device_build) ? client->device_build : "N/A"); + if (client->flags & FLAG_PWN) { recovery_client_free(client); @@ -678,8 +693,8 @@ int idevicerestore_start(struct idevicerestore_client_t* client) /* print iOS information from the manifest */ build_manifest_get_version_information(client->build_manifest, client); - info("Product Version: %s\n", client->version); - info("Product Build: %s Major: %d\n", client->build, client->build_major); + info("IPSW Product Version: %s\n", client->version); + info("IPSW Product Build: %s Major: %d\n", client->build, client->build_major); client->image4supported = is_image4_supported(client); info("Device supports Image4: %s\n", (client->image4supported) ? "true" : "false"); @@ -872,17 +887,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } if (client->mode == MODE_NORMAL && !(client->flags & FLAG_ERASE) && !(client->flags & FLAG_SHSHONLY)) { - plist_t pver = normal_get_lockdown_value(client, NULL, "ProductVersion"); - char *device_version = NULL; - if (pver) { - plist_get_string_val(pver, &device_version); - plist_free(pver); - } - if (device_version && (compare_versions(device_version, client->version) > 0)) { + if (client->device_version && (compare_versions(client->device_version, client->version) > 0)) { if (client->flags & FLAG_INTERACTIVE) { char input[64]; char spaces[16]; - int num_spaces = 13 - strlen(client->version) - strlen(device_version); + int num_spaces = 13 - strlen(client->version) - strlen(client->device_version); memset(spaces, ' ', num_spaces); spaces[num_spaces] = '\0'; printf("################################ [ WARNING ] #################################\n" @@ -893,7 +902,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) "# If you want to take the risk (and have a backup of your important data!) #\n" "# type YES and press ENTER to continue. You have been warned. #\n" "##############################################################################\n", - device_version, client->version, spaces); + client->device_version, client->version, spaces); while (1) { printf("> "); fflush(stdout); @@ -912,7 +921,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } } - free(device_version); } if (client->flags & FLAG_ERASE && client->flags & FLAG_INTERACTIVE) { @@ -1413,12 +1421,10 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client) } free(client->filesystem); } - if (client->version) { - free(client->version); - } - if (client->build) { - free(client->build); - } + free(client->version); + free(client->build); + free(client->device_version); + free(client->device_build); if (client->restore_boot_args) { free(client->restore_boot_args); } From f87ab8baee1c78ba5d3ab6dde4da44ecb93086c4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 8 Nov 2023 11:37:38 +0100 Subject: [PATCH 054/117] .gitignore: Add src/idevicerestore.exe --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a826b421..bdfaa099 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,4 @@ py-compile stamp-h1 src/.libs src/idevicerestore +src/idevicerestore.exe From 6085ed7429986c7dec579fe1f1303ae6651ea1f2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Nov 2023 01:56:08 +0100 Subject: [PATCH 055/117] Print progress for large components (e.g. Cryptex) --- src/common.c | 2 +- src/idevicerestore.h | 1 + src/ipsw.c | 8 ++++---- src/ipsw.h | 2 +- src/restore.c | 41 ++++++++++++++++++++++++++++++++++------- 5 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/common.c b/src/common.c index 0ad775ce..bb534e22 100644 --- a/src/common.c +++ b/src/common.c @@ -467,7 +467,7 @@ void idevicerestore_progress(struct idevicerestore_client_t* client, int step, d client->progress_cb(step, progress, client->progress_cb_data); } else { // we don't want to be too verbose in regular idevicerestore. - if ((step == RESTORE_STEP_UPLOAD_FS) || (step == RESTORE_STEP_VERIFY_FS) || (step == RESTORE_STEP_FLASH_FW)) { + if ((step == RESTORE_STEP_UPLOAD_FS) || (step == RESTORE_STEP_VERIFY_FS) || (step == RESTORE_STEP_FLASH_FW) || (step == RESTORE_STEP_UPLOAD_IMG)) { print_progress_bar(100.0 * progress); } } diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 880562ff..e1a767cb 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -63,6 +63,7 @@ enum { RESTORE_STEP_FLASH_FW, RESTORE_STEP_FLASH_BB, RESTORE_STEP_FUD, + RESTORE_STEP_UPLOAD_IMG, RESTORE_NUM_STEPS }; diff --git a/src/ipsw.c b/src/ipsw.c index 5b1d7323..c25f61d3 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -737,7 +737,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip // EOF break; } - if (send_callback(ctx, buffer, zr) < 0) { + if (send_callback(ctx, buffer, zr, done, total_size) < 0) { error("ERROR: %s: send failed\n", __func__); break; } @@ -773,7 +773,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip free(buffer); return -1; } - send_callback(ctx, buffer, (size_t)rl); + send_callback(ctx, buffer, (size_t)rl, 0, 0); } else { #endif FILE *f = fopen(filepath, "rb"); @@ -792,7 +792,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip error("ERROR: %s: fread failed for %s: %s\n", __func__, filepath, strerror(errno)); break; } - if (send_callback(ctx, buffer, fr) < 0) { + if (send_callback(ctx, buffer, fr, done, total_size) < 0) { error("ERROR: %s: send failed\n", __func__); break; } @@ -812,7 +812,7 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip } // send a NULL buffer to mark end of transfer - send_callback(ctx, NULL, 0); + send_callback(ctx, NULL, 0, done, total_size); return 0; } diff --git a/src/ipsw.h b/src/ipsw.h index 56faf942..f0e11a12 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -44,7 +44,7 @@ void ipsw_close(ipsw_archive_t ipsw); int ipsw_print_info(const char* ipsw); typedef int (*ipsw_list_cb)(void *ctx, ipsw_archive_t ipsw, const char *name, struct stat *stat); -typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size); +typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size, size_t done, size_t total_size); struct ipsw_file_handle { FILE* file; diff --git a/src/restore.c b/src/restore.c index 9e0268a2..7727411d 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3537,7 +3537,13 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil return 0; } -static int _restore_send_file_data(restored_client_t restore, void* data, size_t size) +struct _restore_send_file_data_ctx { + struct idevicerestore_client_t* client; + restored_client_t restore; + int last_progress; +}; + +static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, void* data, size_t size, size_t done, size_t total_size) { plist_t dict = plist_new_dict(); if (data != NULL) { @@ -3547,13 +3553,21 @@ static int _restore_send_file_data(restored_client_t restore, void* data, size_t // Send FileDataDone to mark end of transfer plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); } - restored_error_t restore_error = restored_send(restore, dict); + restored_error_t restore_error = restored_send(rctx->restore, dict); if (restore_error != RESTORE_E_SUCCESS) { plist_free(dict); error("ERROR: %s: Failed to send data (%d)\n", __func__, restore_error); return -1; } plist_free(dict); + if (total_size > 0) { + double progress = (double)done / (double)total_size; + int progress_int = (int)(progress*100.0); + if (progress_int > rctx->last_progress) { + idevicerestore_progress(rctx->client, RESTORE_STEP_UPLOAD_IMG, progress); + rctx->last_progress = progress_int; + } + } return 0; } @@ -3643,12 +3657,17 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i } } - info("Sending %s now...\n", component); + info("Sending %s now (%" PRIu64 " bytes)...\n", component, (uint64_t)size); + + struct _restore_send_file_data_ctx rctx; + rctx.client = client; + rctx.restore = restore; + rctx.last_progress = 0; int64_t i = size; while (i > 0) { int blob_size = i > 8192 ? 8192 : i; - if (_restore_send_file_data(restore, (data + size - i), blob_size) < 0) { + if (_restore_send_file_data(&rctx, (data + size - i), blob_size, size-i, size) < 0) { free(data); error("ERROR: Unable to send component %s data\n", component); return -1; @@ -3657,7 +3676,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i } free(data); - _restore_send_file_data(restore, NULL, 0); + _restore_send_file_data(&rctx, NULL, 0, size-i, size); info("Done sending %s\n", component); return 0; @@ -3733,9 +3752,17 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice return -1; } - info("Sending %s now...\n", component); + uint64_t fsize = 0; + ipsw_get_file_size(client->ipsw, path, &fsize); + + info("Sending %s now (%" PRIu64 " bytes)\n", component, fsize); + + struct _restore_send_file_data_ctx rctx; + rctx.client = client; + rctx.restore = restore; + rctx.last_progress = 0; - if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, restore) < 0) { + if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) { free(path); error("ERROR: Failed to send component %s\n", component); return -1; From 10c15d596eb54c9b97cd7e6323ac8416349ca225 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 9 Nov 2023 20:25:38 +0100 Subject: [PATCH 056/117] Fix update restore by making sure the premanifest is properly generated --- src/idevicerestore.c | 4 ++-- src/img4.c | 11 +++++------ src/tss.c | 31 +++++++++++++++++++++++++------ 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index b2185103..9bc9f8b4 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1981,7 +1981,7 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_ plist_t overrides = plist_new_dict(); plist_dict_set_item(overrides, "@APTicket", plist_new_bool(1)); plist_dict_set_item(overrides, "ApProductionMode", plist_new_uint(0)); - plist_dict_set_item(overrides, "ApSecurityDomain", plist_new_uint(0)); + plist_dict_set_item(overrides, "ApSecurityDomain", plist_new_uint(1)); plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(0)); plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(0)); @@ -2005,7 +2005,7 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_ return -1; } - plist_dict_set_item(parameters, "_OnlyFWComponents", plist_new_bool(1)); + plist_dict_set_item(parameters, "_OnlyFWOrTrustedComponents", plist_new_bool(1)); /* add tags from manifest */ if (tss_request_add_ap_tags(request, parameters, NULL) < 0) { diff --git a/src/img4.c b/src/img4.c index c21a0753..56b04964 100644 --- a/src/img4.c +++ b/src/img4.c @@ -844,13 +844,12 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* comp = _img4_get_component_tag(key); } if (!comp) { - error("ERROR: %s: Unhandled component '%s' - can't create manifest\n", __func__, key); - free(iter); - free(buf); - return -1; + debug("DEBUG: %s: Unhandled component '%s'\n", __func__, key); + _manifest_write_component(&p, &length, key, val); + } else { + debug("DEBUG: found component %s (%s)\n", comp, key); + _manifest_write_component(&p, &length, comp, val); } - debug("DEBUG: found component %s (%s)\n", comp, key); - _manifest_write_component(&p, &length, comp, val); } free(key); } while (val); diff --git a/src/tss.c b/src/tss.c index 5e676f4b..e9d68f39 100644 --- a/src/tss.c +++ b/src/tss.c @@ -582,8 +582,15 @@ int tss_request_add_ap_recovery_tags(plist_t request, plist_t parameters, plist_ continue; } - if (!_plist_dict_get_bool(info_dict, "IsFirmwarePayload") && !_plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") && !_plist_dict_get_bool(info_dict, "IsFUDFirmware")) { - debug("DEBUG: %s: Skipping '%s' as it is neither firmware nor secondary nor FUD firmware payload\n", __func__, key); + if (!_plist_dict_get_bool(info_dict, "IsFirmwarePayload") + && !_plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") + && !_plist_dict_get_bool(info_dict, "IsFUDFirmware") + && !_plist_dict_get_bool(info_dict, "IsLoadedByiBoot") + && !_plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") + && !_plist_dict_get_bool(info_dict, "IsiBootEANFirmware") + && !_plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware")) + { + debug("DEBUG: %s: Skipping '%s' as it is not a firmware payload\n", __func__, key); continue; } } @@ -679,14 +686,26 @@ int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrid } } - if (_plist_dict_get_bool(parameters, "_OnlyFWComponents")) { + int is_fw_payload = _plist_dict_get_bool(info_dict, "IsFirmwarePayload") + || _plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") + || _plist_dict_get_bool(info_dict, "IsFUDFirmware") + || _plist_dict_get_bool(info_dict, "IsLoadedByiBoot") + || _plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") + || _plist_dict_get_bool(info_dict, "IsiBootEANFirmware") + || _plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware"); + + if (_plist_dict_get_bool(parameters, "_OnlyFWOrTrustedComponents")) { + if (!_plist_dict_get_bool(manifest_entry, "Trusted") && !is_fw_payload) { + debug("DEBUG: %s: Skipping '%s' as it is neither firmware payload nor trusted\n", __func__, key); + continue; + } + } else if (_plist_dict_get_bool(parameters, "_OnlyFWComponents")) { if (!_plist_dict_get_bool(manifest_entry, "Trusted")) { debug("DEBUG: %s: Skipping '%s' as it is not trusted\n", __func__, key); continue; } - - if (!_plist_dict_get_bool(info_dict, "IsFirmwarePayload") && !_plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") && !_plist_dict_get_bool(info_dict, "IsFUDFirmware")) { - debug("DEBUG: %s: Skipping '%s' as it is neither firmware nor secondary nor FUD firmware payload\n", __func__, key); + if (!is_fw_payload) { + debug("DEBUG: %s: Skipping '%s' as it is not a firmware payload\n", __func__, key); continue; } } From 85ea3378255cc15e3f39365018f45a42d7469375 Mon Sep 17 00:00:00 2001 From: tihmstar Date: Wed, 15 Nov 2023 00:14:43 +0100 Subject: [PATCH 057/117] asr: Fix sending payload without checksum --- src/asr.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/asr.c b/src/asr.c index 304e8a32..bf15dc21 100644 --- a/src/asr.c +++ b/src/asr.c @@ -349,11 +349,12 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) SHA1_Init(&sha1); } - int size = 0; i = length; int retry = 3; while(i > 0 && retry >= 0) { - size = ASR_PAYLOAD_CHUNK_SIZE; + uint32_t size = ASR_PAYLOAD_CHUNK_SIZE; + uint32_t sendsize = 0; + if (i < ASR_PAYLOAD_CHUNK_SIZE) { size = i; } @@ -364,11 +365,12 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) continue; } + sendsize = size; if (asr->checksum_chunks) { SHA1((unsigned char*)data, size, (unsigned char*)(data+size)); + sendsize += 20; } - - if (asr_send_buffer(asr, data, size+20) < 0) { + if (asr_send_buffer(asr, data, sendsize) < 0) { error("ERROR: Unable to send filesystem payload\n"); retry--; continue; From 83600e92240cd2538cd82f90ed03601731b1b0d9 Mon Sep 17 00:00:00 2001 From: tihmstar Date: Wed, 15 Nov 2023 00:41:21 +0100 Subject: [PATCH 058/117] restore: Fix UaF `fsname_base` points inside the dynamically allocated `path` which is freed before `fsname_base` is used, creating a use-after-free condition. This commits makes sure to free `path` only after it is no longer needed. --- src/restore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/restore.c b/src/restore.c index 7727411d..7fa104bc 100644 --- a/src/restore.c +++ b/src/restore.c @@ -913,11 +913,11 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de } if (client->filesystem) { char* path = strdup(client->filesystem); - char* fsname_base = path_get_basename(path); + const char* fsname_base = path_get_basename(path); char* parent_dir = dirname(path); ipsw_dummy = ipsw_open(parent_dir); - free(path); file = ipsw_file_open(ipsw_dummy, fsname_base); + free(path); } else { file = ipsw_file_open(client->ipsw, fsname); } From acecac3cb8b66fddd9dc811c920c6b7dfb969895 Mon Sep 17 00:00:00 2001 From: tihmstar Date: Wed, 15 Nov 2023 00:45:53 +0100 Subject: [PATCH 059/117] Change path_get_basename()'s return type to const char* This makes it clear that the return value is immutable and moreover suggests that the return vale is not allocated and thus should be treated carefully. --- src/common.c | 6 +++--- src/common.h | 2 +- src/idevicerestore.c | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/common.c b/src/common.c index bb534e22..c3c9d685 100644 --- a/src/common.c +++ b/src/common.c @@ -696,10 +696,10 @@ int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char * return 0; } -char* path_get_basename(char* path) +const char* path_get_basename(char* path) { #ifdef WIN32 - char *p = path + strlen(path); + const char *p = path + strlen(path); while (p > path) { if ((*p == '/') || (*p == '\\')) { return p+1; @@ -708,7 +708,7 @@ char* path_get_basename(char* path) } return p; #else - char *p = strrchr(path, '/'); + const char *p = strrchr(path, '/'); return p ? p + 1 : path; #endif } diff --git a/src/common.h b/src/common.h index f7b1dcd1..974d5054 100644 --- a/src/common.h +++ b/src/common.h @@ -197,7 +197,7 @@ int _plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char * int _plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); -char* path_get_basename(char* path); +const char* path_get_basename(char* path); #ifdef __cplusplus } diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 9bc9f8b4..064c5030 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -987,8 +987,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (stat(client->cache_dir, &st) < 0) { mkdir_with_parents(client->cache_dir, 0755); } - char* ipsw_basename = path_get_basename(client->ipsw->path); - ipsw_basename = strdup(ipsw_basename); + char* ipsw_basename = strdup(path_get_basename(client->ipsw->path)); char* p = strrchr(ipsw_basename, '.'); if (p && isalpha(*(p+1))) { *p = '\0'; From ecae6c6e8ca6b6bad080a1c73f10ffd0e67d75a7 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 15 Nov 2023 13:29:16 +0100 Subject: [PATCH 060/117] Change path_get_basename arg to const too --- src/common.c | 2 +- src/common.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common.c b/src/common.c index c3c9d685..9a739940 100644 --- a/src/common.c +++ b/src/common.c @@ -696,7 +696,7 @@ int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char * return 0; } -const char* path_get_basename(char* path) +const char* path_get_basename(const char* path) { #ifdef WIN32 const char *p = path + strlen(path); diff --git a/src/common.h b/src/common.h index 974d5054..493b1df4 100644 --- a/src/common.h +++ b/src/common.h @@ -197,7 +197,7 @@ int _plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char * int _plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); -const char* path_get_basename(char* path); +const char* path_get_basename(const char* path); #ifdef __cplusplus } From c6a9359f7f1bd532d51fbab79f47e230afe6f5f5 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 21 Nov 2023 00:33:48 +0100 Subject: [PATCH 061/117] Update libzip API usage to use non-deprecated functions --- src/restore.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/restore.c b/src/restore.c index 7fa104bc..772f57fd 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1515,7 +1515,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned uint64_t fsize = 0; uint64_t blob_size = 0; int zerr = 0; - int zindex = -1; + int64_t zindex = -1; struct zip_stat zstat; struct zip_file* zfile = NULL; struct zip* za = NULL; @@ -1537,7 +1537,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } int is_fls = 0; - int signed_file_idxs[16]; + int64_t signed_file_idxs[16]; int signed_file_count = 0; char* key = NULL; plist_t node = NULL; @@ -1566,13 +1566,13 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned zip_stat_init(&zstat); if (zip_stat_index(za, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index failed for index %d\n", zindex); + error("ERROR: zip_stat_index failed for index %" PRIi64 "\n", zindex); goto leave; } zfile = zip_fopen_index(za, zindex, 0); if (zfile == NULL) { - error("ERROR: zip_fopen_index failed for index %d\n", zindex); + error("ERROR: zip_fopen_index failed for index %" PRIi64 "\n", zindex); goto leave; } @@ -1652,7 +1652,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned goto leave; } - if (zip_replace(za, zindex, zs) == -1) { + if (zip_file_replace(za, zindex, zs, 0) == -1) { error("ERROR: could not update signed '%s' in archive\n", signfn); goto leave; } @@ -1670,9 +1670,10 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned free(iter); // remove everything but required files - int i, j, keep, numf = zip_get_num_files(za); + int64_t i, numf = zip_get_num_entries(za, 0); for (i = 0; i < numf; i++) { - keep = 0; + int j; + int keep = 0; // check for signed file index for (j = 0; j < signed_file_count; j++) { if (i == signed_file_idxs[j]) { @@ -1706,13 +1707,13 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned zip_stat_init(&zstat); if (zip_stat_index(za, zindex, 0, &zstat) != 0) { - error("ERROR: zip_stat_index failed for index %d\n", zindex); + error("ERROR: zip_stat_index failed for index %" PRIi64 "\n", zindex); goto leave; } zfile = zip_fopen_index(za, zindex, 0); if (zfile == NULL) { - error("ERROR: zip_fopen_index failed for index %d\n", zindex); + error("ERROR: zip_fopen_index failed for index %" PRIi64 "\n", zindex); goto leave; } @@ -1771,7 +1772,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned goto leave; } - if (zip_replace(za, zindex, zs) == -1) { + if (zip_file_replace(za, zindex, zs, 0) == -1) { error("ERROR: could not update archive with ticketed ebl.fls\n"); goto leave; } @@ -1792,7 +1793,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } blob = NULL; - if (zip_add(za, "bbticket.der", zs) == -1) { + if (zip_file_add(za, "bbticket.der", zs, ZIP_FL_OVERWRITE) == -1) { error("ERROR: could not add bbticket.der to archive\n"); goto leave; } From 8a5abb99170b324b0fc5a00928ba2ac78a7afc98 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 27 Nov 2023 00:14:27 +0800 Subject: [PATCH 062/117] restore: Only print progress bar for images larger than 16 MB --- src/restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 772f57fd..1261147f 100644 --- a/src/restore.c +++ b/src/restore.c @@ -3561,7 +3561,7 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi return -1; } plist_free(dict); - if (total_size > 0) { + if (total_size > 0x1000000) { double progress = (double)done / (double)total_size; int progress_int = (int)(progress*100.0); if (progress_int > rctx->last_progress) { From 14fc14a2a0e9ba0e224b6bc318b8fa773a8dad8c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 13 Jan 2024 12:12:30 +0100 Subject: [PATCH 063/117] [github-actions] Windows: build with static libcurl --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9a92883b..75eac9a3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -271,7 +271,7 @@ jobs: echo "LIBZIP_CFLAGS=-I`pwd`/deps/include" >> $GITHUB_ENV echo "LIBZIP_LIBS=`pwd`/deps/lib/libzip.a /${{env.dest}}/lib/libbz2.a /${{env.dest}}/lib/liblzma.a " >> $GITHUB_ENV - name: autogen - run: ./autogen.sh CC=gcc CXX=g++ --without-openssl libzip_VERSION=1.7.1 libzip_CFLAGS="${{env.LIBZIP_CFLAGS}}" libzip_LIBS="${{env.LIBZIP_LIBS}}" zlib_LIBS="/${{env.dest}}/lib/libz.a" + run: ./autogen.sh CC=gcc CXX=g++ libzip_VERSION=1.7.1 libzip_CFLAGS="${{env.LIBZIP_CFLAGS}}" libzip_LIBS="${{env.LIBZIP_LIBS}}" zlib_LIBS="/${{env.dest}}/lib/libz.a" libcurl_CFLAGS="-I/${{env.dest}}/include -DCURL_STATICLIB" libcurl_LIBS="/${{env.dest}}/lib/libcurl.a /${{env.dest}}/lib/libssh2.a /${{env.dest}}/lib/libpsl.a /${{env.dest}}/lib/libidn2.a /${{env.dest}}/lib/libunistring.a /${{env.dest}}/lib/libnghttp2.a /${{env.dest}}/lib/libbrotlidec.a /${{env.dest}}/lib/libbrotlicommon.a /${{env.dest}}/lib/libiconv.a /${{env.dest}}/lib/libzstd.a -lws2_32 -lcrypt32 -lwldap32 -lbcrypt -lssl -lcrypto" - name: make run: make - name: make install From a2b8443b48dd885a9059e6e051ff0d6c36ef8f46 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 15 Jan 2024 00:29:49 +0100 Subject: [PATCH 064/117] libcurl build --- .github/workflows/curl.yml | 58 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/curl.yml diff --git a/.github/workflows/curl.yml b/.github/workflows/curl.yml new file mode 100644 index 00000000..a2974762 --- /dev/null +++ b/.github/workflows/curl.yml @@ -0,0 +1,58 @@ +name: build-libcurl-static + +on: [push] + +jobs: + build-windows: + runs-on: windows-2019 + defaults: + run: + shell: msys2 {0} + strategy: + fail-fast: false + matrix: + include: [ + { msystem: MINGW64, arch: x86_64 }, + { msystem: MINGW32, arch: i686 } + ] + steps: + - uses: msys2/setup-msys2@v2 + with: + msystem: ${{ matrix.msystem }} + release: false + update: false + install: >- + base-devel + git + mingw-w64-${{ matrix.arch }}-gcc + make + libtool + autoconf + automake-wrapper + liblzma + - name: prepare environment + run: | + dest=`echo ${{ matrix.msystem }} |tr [:upper:] [:lower:]` + echo "dest=$dest" >> $GITHUB_ENV + echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV + - name: fetch curl source + run: | + curl -Ls -o curl-8.1.0.tar.bz2 https://github.com/curl/curl/releases/download/curl-8_1_0/curl-8.1.0.tar.bz2 + tar xjf curl-8.1.0.tar.bz2 + - name: configure curl + run: | + cd curl-8.1.0 + ./configure --disable-ldap --disable-ldaps --disable-rtsp --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-mqtt --disable-manual --disable-threaded-resolver --disable-pthreads --disable-sspi --disable-aws --disable-ntlm --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --disable-doh --disable-mime --disable-bindlocal --disable-dnsshuffle --disable-alt-svc --disable-hsts --disable-websockets --with-openssl --without-brotli --without-libidn2 --without-ngtcp2 --without-quiche --without-msh3 --without-nghttp2 --without-libpsl + - name: build libcurl + run: | + CURDIR=`pwd` + cd curl-8.1.0/lib + make + cp .libs/libcurl.a . + cd .. + tar cf $CURDIR/libcurl-static.tar lib/libcurl.a include/curl/*.h + - name: publish artifact + uses: actions/upload-artifact@v3 + with: + name: libcurl_${{ matrix.arch }}-${{ env.dest }} + path: libcurl-static.tar From cba2d5e0a918184c0145e371eb3dd9e4ae52cd7b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 15 Jan 2024 00:59:16 +0100 Subject: [PATCH 065/117] update build --- .github/workflows/build.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 75eac9a3..696dcda8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -270,8 +270,17 @@ jobs: tar -C deps -xjf $FILENAME echo "LIBZIP_CFLAGS=-I`pwd`/deps/include" >> $GITHUB_ENV echo "LIBZIP_LIBS=`pwd`/deps/lib/libzip.a /${{env.dest}}/lib/libbz2.a /${{env.dest}}/lib/liblzma.a " >> $GITHUB_ENV + FILENAME="libcurl-8.1.0-static.tar.bz2" + curl -o $FILENAME.b64 -Ls "https://gist.github.com/nikias/6c397a0a2f4f4eafd91b81cccd22b761/raw/85216e60af6787f3b351291165eb91bd585ff09a/libcurl-8.1.0-static-${{matrix.arch}}-${{env.dest}}.tar.bz2" + base64 -d < $FILENAME.b64 > $FILENAME + tar -C deps -xjf $FILENAME + echo "LIBCURL_CFLAGS=-I`pwd`/deps/include -DCURL_STATICLIB" >> $GITHUB_ENV + echo "LIBCURL_LIBS=`pwd`/deps/lib/libcurl.a /${{env.dest}}/lib/libzstd.a -lws2_32 -lcrypt32 -lwldap32 -lbcrypt -lssl -lcrypto" >> $GITHUB_ENV - name: autogen - run: ./autogen.sh CC=gcc CXX=g++ libzip_VERSION=1.7.1 libzip_CFLAGS="${{env.LIBZIP_CFLAGS}}" libzip_LIBS="${{env.LIBZIP_LIBS}}" zlib_LIBS="/${{env.dest}}/lib/libz.a" libcurl_CFLAGS="-I/${{env.dest}}/include -DCURL_STATICLIB" libcurl_LIBS="/${{env.dest}}/lib/libcurl.a /${{env.dest}}/lib/libssh2.a /${{env.dest}}/lib/libpsl.a /${{env.dest}}/lib/libidn2.a /${{env.dest}}/lib/libunistring.a /${{env.dest}}/lib/libnghttp2.a /${{env.dest}}/lib/libbrotlidec.a /${{env.dest}}/lib/libbrotlicommon.a /${{env.dest}}/lib/libiconv.a /${{env.dest}}/lib/libzstd.a -lws2_32 -lcrypt32 -lwldap32 -lbcrypt -lssl -lcrypto" + run: | + ./autogen.sh CC=gcc CXX=g++ \ + libzip_VERSION=1.7.1 libzip_CFLAGS="${{env.LIBZIP_CFLAGS}}" libzip_LIBS="${{env.LIBZIP_LIBS}}" \ + zlib_LIBS="/${{env.dest}}/lib/libz.a" libcurl_CFLAGS="${{env.LIBCURL_CFLAGS}}" libcurl_LIBS="$LIBCURL_LIBS" - name: make run: make - name: make install From fdbf383a52111014f7e41fde0f1e8ee209679412 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 8 Mar 2024 12:23:03 +0100 Subject: [PATCH 066/117] Make sure to extract the build manifest before doing restore mode checks Otherwise we could set tss_enabled to 0 but the extraction would re-enable it. --- src/idevicerestore.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 064c5030..af5dbf3e 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -642,6 +642,21 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return 0; } + // extract buildmanifest + if (client->flags & FLAG_CUSTOM) { + info("Extracting Restore.plist from IPSW\n"); + if (ipsw_extract_restore_plist(client->ipsw, &client->build_manifest) < 0) { + error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw->path); + return -1; + } + } else { + info("Extracting BuildManifest from IPSW\n"); + if (ipsw_extract_build_manifest(client->ipsw, &client->build_manifest, &tss_enabled) < 0) { + error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw->path); + return -1; + } + } + if (client->mode == MODE_RESTORE) { if (client->flags & FLAG_ALLOW_RESTORE_MODE) { tss_enabled = 0; @@ -668,20 +683,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } - // extract buildmanifest - if (client->flags & FLAG_CUSTOM) { - info("Extracting Restore.plist from IPSW\n"); - if (ipsw_extract_restore_plist(client->ipsw, &client->build_manifest) < 0) { - error("ERROR: Unable to extract Restore.plist from %s. Firmware file might be corrupt.\n", client->ipsw->path); - return -1; - } - } else { - info("Extracting BuildManifest from IPSW\n"); - if (ipsw_extract_build_manifest(client->ipsw, &client->build_manifest, &tss_enabled) < 0) { - error("ERROR: Unable to extract BuildManifest from %s. Firmware file might be corrupt.\n", client->ipsw->path); - return -1; - } - } idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.8); /* check if device type is supported by the given build manifest */ From 012e0aa3d458a44ae3808707b9d5b6038d9095a6 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 23 Mar 2024 00:49:55 +0100 Subject: [PATCH 067/117] Fix some variable types for more consistency --- src/dfu.c | 6 +++--- src/dfu.h | 4 ++-- src/idevicerestore.c | 14 +++++++------- src/idevicerestore.h | 4 ++-- src/normal.c | 8 ++++---- src/normal.h | 4 ++-- src/recovery.c | 4 ++-- src/recovery.h | 4 ++-- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index 4487ade0..8602bc0c 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -238,7 +238,7 @@ int dfu_is_image4_supported(struct idevicerestore_client_t* client) return (device_info->ibfl & IBOOT_FLAG_IMAGE4_AWARE); } -int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { if(client->dfu == NULL) { if (dfu_client_new(client) < 0) { @@ -263,7 +263,7 @@ int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** non return 0; } -int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { if(client->dfu == NULL) { if (dfu_client_new(client) < 0) { @@ -417,7 +417,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide /* get nonce */ unsigned char* nonce = NULL; - int nonce_size = 0; + unsigned int nonce_size = 0; int nonce_changed = 0; if (dfu_get_ap_nonce(client, &nonce, &nonce_size) < 0) { error("ERROR: Unable to get ApNonce from device!\n"); diff --git a/src/dfu.h b/src/dfu.h index 67124429..f6174abb 100644 --- a/src/dfu.h +++ b/src/dfu.h @@ -44,8 +44,8 @@ int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffe int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component); int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid); int dfu_is_image4_supported(struct idevicerestore_client_t* client); -int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); -int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); +int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); +int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity); diff --git a/src/idevicerestore.c b/src/idevicerestore.c index af5dbf3e..e71dea4e 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1064,7 +1064,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (client->build_major > 8) { unsigned char* nonce = NULL; - int nonce_size = 0; + unsigned int nonce_size = 0; if (get_ap_nonce(client, &nonce, &nonce_size) < 0) { /* the first nonce request with older firmware releases can fail and it's OK */ info("NOTE: Unable to get nonce from device\n"); @@ -1265,7 +1265,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (!client->image4supported && (client->build_major > 8)) { // we need another tss request with nonce. unsigned char* nonce = NULL; - int nonce_size = 0; + unsigned int nonce_size = 0; int nonce_changed = 0; if (get_ap_nonce(client, &nonce, &nonce_size) < 0) { error("ERROR: Unable to get nonce from device!\n"); @@ -1810,7 +1810,7 @@ int is_image4_supported(struct idevicerestore_client_t* client) return res; } -int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { int mode = _MODE_UNKNOWN; @@ -1861,7 +1861,7 @@ int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, return 0; } -int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { int mode = _MODE_UNKNOWN; @@ -2102,7 +2102,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; - int sep_nonce_size = 0; + unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { @@ -2226,7 +2226,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; - int sep_nonce_size = 0; + unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); /* ApSepNonce */ @@ -2405,7 +2405,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; - int sep_nonce_size = 0; + unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { diff --git a/src/idevicerestore.h b/src/idevicerestore.h index e1a767cb..5afcf1af 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -93,8 +93,8 @@ const char* idevicerestore_get_error(void); irecv_device_t get_irecv_device(struct idevicerestore_client_t* client); int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid); int is_image4_supported(struct idevicerestore_client_t* client); -int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); -int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); +int get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); +int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int get_tss_response(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* tss); int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* tss); int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* tss); diff --git a/src/normal.c b/src/normal.c index b7f9f9d7..efe8f03d 100644 --- a/src/normal.c +++ b/src/normal.c @@ -323,7 +323,7 @@ plist_t normal_get_lockdown_value(struct idevicerestore_client_t* client, const return node; } -static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const char* key, unsigned char** nonce, int* nonce_size) +static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const char* key, unsigned char** nonce, unsigned int* nonce_size) { plist_t nonce_node = normal_get_lockdown_value(client, NULL, key); @@ -334,18 +334,18 @@ static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const uint64_t n_size = 0; plist_get_data_val(nonce_node, (char**)nonce, &n_size); - *nonce_size = (int)n_size; + *nonce_size = (unsigned int)n_size; plist_free(nonce_node); return 0; } -int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { return normal_get_nonce_by_key(client, "SEPNonce", nonce, nonce_size); } -int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { return normal_get_nonce_by_key(client, "ApNonce", nonce, nonce_size); } diff --git a/src/normal.h b/src/normal.h index 85464dbc..7741ac5f 100644 --- a/src/normal.h +++ b/src/normal.h @@ -36,8 +36,8 @@ int normal_check_mode(struct idevicerestore_client_t* client); irecv_device_t normal_get_irecv_device(struct idevicerestore_client_t* client); int normal_enter_recovery(struct idevicerestore_client_t* client); int normal_is_image4_supported(struct idevicerestore_client_t* client); -int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); -int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); +int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); +int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info); plist_t normal_get_lockdown_value(struct idevicerestore_client_t* client, const char* domain, const char* key); int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_t manifest); diff --git a/src/recovery.c b/src/recovery.c index 02f56898..e3fb4d19 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -537,7 +537,7 @@ int recovery_is_image4_supported(struct idevicerestore_client_t* client) return (device_info->ibfl & IBOOT_FLAG_IMAGE4_AWARE); } -int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { if(client->recovery == NULL) { if (recovery_client_new(client) < 0) { @@ -562,7 +562,7 @@ int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char* return 0; } -int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { if(client->recovery == NULL) { if (recovery_client_new(client) < 0) { diff --git a/src/recovery.h b/src/recovery.h index 92214af3..d7413e0c 100644 --- a/src/recovery.h +++ b/src/recovery.h @@ -55,8 +55,8 @@ int recovery_send_reset(struct idevicerestore_client_t* client); int recovery_send_ticket(struct idevicerestore_client_t* client); int recovery_set_autoboot(struct idevicerestore_client_t* client, int enable); int recovery_is_image4_supported(struct idevicerestore_client_t* client); -int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); -int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size); +int recovery_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); +int recovery_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); #ifdef __cplusplus From babf9add7f1f5df7d8093e7d26d73b674ecd246b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 23 Mar 2024 01:06:37 +0100 Subject: [PATCH 068/117] tss: Update libauthinstall verison string --- src/tss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tss.c b/src/tss.c index e9d68f39..80591e7f 100644 --- a/src/tss.c +++ b/src/tss.c @@ -35,7 +35,7 @@ #include "endianness.h" -#define AUTH_VERSION "914.120.2" +#define AUTH_VERSION "973.40.2" #ifdef WIN32 #define TSS_CLIENT_VERSION_STRING "libauthinstall_Win-"AUTH_VERSION"" From e4a5ac4114177293e3a1b555ee767377b21d4432 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 23 Mar 2024 04:25:21 +0100 Subject: [PATCH 069/117] Add support for Port DFU device restore --- configure.ac | 4 +- src/Makefile.am | 1 + src/ace3.c | 244 +++++++++++++++++++++++++++++++++++++++++++ src/ace3.h | 17 +++ src/common.c | 1 + src/common.h | 2 + src/dfu.c | 83 +++++++++++++++ src/dfu.h | 4 + src/idevicerestore.c | 157 ++++++++++++++++++++++++++++ 9 files changed, 511 insertions(+), 2 deletions(-) create mode 100644 src/ace3.c create mode 100644 src/ace3.h diff --git a/configure.ac b/configure.ac index 572e2804..1cd58444 100644 --- a/configure.ac +++ b/configure.ac @@ -15,11 +15,11 @@ if test -z $PACKAGE_VERSION; then fi # Minimum package versions -LIBIRECOVERY_VERSION=1.0.1 +LIBIRECOVERY_VERSION=1.2.0 LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.3.0 -LIMD_GLUE_VERSION=1.0.0 +LIMD_GLUE_VERSION=1.2.0 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 OPENSSL_VERSION=0.9.8 diff --git a/src/Makefile.am b/src/Makefile.am index 019424ba..722487a2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -44,6 +44,7 @@ idevicerestore_SOURCES = \ restore.c restore.h \ asr.c asr.h \ fdr.c fdr.h \ + ace3.c ace3.h \ limera1n_payload.h \ limera1n.c limera1n.h \ download.c download.h \ diff --git a/src/ace3.c b/src/ace3.c new file mode 100644 index 00000000..b96e6b4f --- /dev/null +++ b/src/ace3.c @@ -0,0 +1,244 @@ +/* + * ace3.c + * Functions to handle Ace3/uarp firmware format + * + * Copyright (c) 2024 Nikias Bassen, All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include + +#include "common.h" +#include "ace3.h" +#include "endianness.h" + +static uint32_t crc_buffer(const unsigned char* buffer, unsigned int bufsize, unsigned int salt) +{ + uint32_t result; + unsigned int i; + unsigned int j; + + if ( !buffer ) + return 0xFFFFFFFF; + result = salt; + for (i = 0; i < bufsize; ++i) { + for (j = 0; j != 8; ++j) { + unsigned int tmp0 = 2 * result; + unsigned int tmp1 = *(unsigned char*)(buffer + i); + unsigned int tmp2 = ((unsigned int)result >> 31) ^ ((tmp1 >> j) & 1); + result = (tmp2 + 2 * result) ^ 0x4C11DB6; + if (!tmp2) + result = tmp0; + } + } + return result; +} + +int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, unsigned char** bin_out, size_t* bin_size) +{ + struct ace3bin_header { + uint32_t magic; // 0xACE00003 + uint32_t unk4; // 0x00203400 + uint32_t unk8; // 0x00002800 + uint32_t header_size; // 0x00000040 + uint32_t data1_size; + uint32_t data2_size; + uint32_t im4m_offset; + uint32_t im4m_dl_size; + uint32_t content_size; + uint32_t crc; + uint64_t fill1; // 0xFFFFFFFFFFFFFFFF + uint64_t fill2; // 0xFFFFFFFFFFFFFFFF + uint64_t fill3; // 0xFFFFFFFFFFFFFFFF + }; + + struct uarp_header { + uint32_t unk_00; // BE 0x00000002 + uint32_t header_size; // BE usually 0x0000002C + uint32_t plist_offset; // BE + uint32_t unk_0c; // 0 + uint32_t unk_10; // 0 + uint32_t unk_14; // 0 + uint32_t unk_18; // 0 + uint32_t c_offset; // BE + uint32_t unk_20; // 0 + uint32_t toc_offset; // BE usually 0x0000002c + uint32_t toc_size; // BE + }; + struct uarp_toc_entry { + uint32_t this_size; // BE usually 0x28 + uint32_t fourcc; // 'PT01' or similar + uint32_t index; // BE starting with 0, increment+1 for each entry + uint32_t unk_0c; // BE usually not zero + uint32_t unk_10; // BE usually 0 + uint32_t unk_14; // BE usually 0 + uint32_t unk_18; // BE other offset, not sure + uint32_t unk_1c; // BE usually 0 + uint32_t offset; // BE + uint32_t size; // + }; + + plist_t p_im4m = plist_dict_get_item(tss, "USBPortController1,Ticket"); + uint64_t im4m_size = 0; + const char* im4m = plist_get_data_ptr(p_im4m, &im4m_size); + + struct uarp_header* uarp_hdr = (struct uarp_header*)uarp_fw; + uint32_t uarp_hdr_size = be32toh(uarp_hdr->header_size); + uint32_t plist_offset = be32toh(uarp_hdr->plist_offset); + uint32_t plist_size = uarp_size - plist_offset; + nskeyedarchive_t ka = nskeyedarchive_new_from_data(uarp_fw + plist_offset, plist_size); + if (!ka) { + return -1; + } + plist_t uarp_dict = nskeyedarchive_to_plist(ka); + nskeyedarchive_free(ka); + + // find the corresponding entries for given BoardID+PREV + + char* payload_4cc = NULL; + char* data_payload_4ccs = NULL; + + plist_t sb_payloads = plist_dict_get_item(uarp_dict, "SuperBinary Payloads"); + if (PLIST_IS_ARRAY(sb_payloads)) { + plist_array_iter iter = NULL; + plist_array_new_iter(sb_payloads, &iter); + plist_t payload = NULL; + do { + plist_array_next_item(sb_payloads, iter, &payload); + if (!payload) { + break; + } + plist_t meta = plist_dict_get_item(payload, "Payload MetaData"); + if (!PLIST_IS_DICT(meta)) { + continue; + } + plist_t prefix = plist_dict_get_item(meta, "Personalization Manifest Prefix"); + if (!PLIST_IS_STRING(prefix)) { + continue; + } + if (strcmp(plist_get_string_ptr(prefix, NULL), "USBPortController") != 0) { + continue; + } + plist_t p_boardid = plist_dict_get_item(meta, "Personalization Board ID (64 bits)"); + if (!PLIST_IS_INT(p_boardid)) { + continue; + } + uint64_t boardid = 0; + plist_get_uint_val(p_boardid, &boardid); + if (boardid == bdid) { + plist_t p4cc = plist_dict_get_item(payload, "Payload 4CC"); + plist_get_string_val(p4cc, &payload_4cc); + plist_t matching = plist_dict_get_item(meta, "Personalization Matching Data"); + if (PLIST_IS_ARRAY(matching)) { + plist_array_iter iter2 = NULL; + plist_array_new_iter(matching, &iter2); + plist_t match = NULL; + do { + plist_array_next_item(matching, iter2, &match); + if (!PLIST_IS_DICT(match)) { + break; + } + uint64_t minrev = 0; + plist_t p_min = plist_dict_get_item(match, "Personalization Matching Data Product Revision Minimum"); + plist_get_uint_val(p_min, &minrev); + uint64_t maxrev = 0; + plist_t p_max = plist_dict_get_item(match, "Personalization Matching Data Product Revision Maximum"); + plist_get_uint_val(p_max, &maxrev); + if (prev >= minrev && prev <= maxrev) { + plist_t tags = plist_dict_get_item(match, "Personalization Matching Data Payload Tags"); + plist_get_string_val(tags, &data_payload_4ccs); + break; + } + } while (match); + plist_mem_free(iter2); + } + break; + } + } while (payload); + plist_mem_free(iter); + } + if (!payload_4cc) { + printf("Failed to get payload 4cc\n"); + return -1; + } + if (!data_payload_4ccs) { + printf("Failed to get data payload 4ccs\n"); + return -1; + } + + // now find the blobs in UARP data + uint32_t dl_offset = 0; + uint32_t dl_size = 0; + uint32_t data1_offset = 0; + uint32_t data1_size = 0; + uint32_t data2_offset = 0; + uint32_t data2_size = 0; + uint32_t toc_offset = be32toh(uarp_hdr->toc_offset); + uint32_t toc_size = be32toh(uarp_hdr->toc_size); + const unsigned char* p = uarp_fw + uarp_hdr_size; + while (p < uarp_fw + toc_size) { + struct uarp_toc_entry* entry = (struct uarp_toc_entry*)p; + uint32_t te_size = be32toh(entry->this_size); + if (strncmp((char*)&(entry->fourcc), payload_4cc, 4) == 0) { + dl_offset = be32toh(entry->offset); + dl_size = be32toh(entry->size); + } else if (strncmp((char*)&(entry->fourcc), data_payload_4ccs, 4) == 0) { + data1_offset = be32toh(entry->offset); + data1_size = be32toh(entry->size); + } else if (strncmp((char*)&(entry->fourcc), data_payload_4ccs+5, 4) == 0) { + data2_offset = be32toh(entry->offset); + data2_size = be32toh(entry->size); + } + p += te_size; + } + + uint32_t content_size = data1_size + data2_size + im4m_size + dl_size; + + *bin_out = (unsigned char*)malloc(0x40 + content_size); + struct ace3bin_header* hdr = (struct ace3bin_header*)(*bin_out); + hdr->magic = htole32(0xACE00003); + hdr->unk4 = htole32(0x00203400); + hdr->unk8 = htole32(0x00002800); + hdr->header_size = htole32(0x40); + hdr->data1_size = htole32(data1_size); + hdr->data2_size = htole32(data2_size);; + hdr->im4m_offset = htole32(0x40 + data1_size + data2_size); + hdr->im4m_dl_size = htole32(im4m_size + dl_size); + hdr->content_size = htole32(content_size); + hdr->crc = 0; + hdr->fill1 = 0xFFFFFFFFFFFFFFFFLL; + hdr->fill2 = 0xFFFFFFFFFFFFFFFFLL; + hdr->fill3 = 0xFFFFFFFFFFFFFFFFLL; + + // write data1 payload + memcpy(*bin_out + 0x40, uarp_fw + data1_offset, data1_size); + // write data2 payload + memcpy(*bin_out + 0x40 + data1_size, uarp_fw + data2_offset, data2_size); + // write IM4M + memcpy(*bin_out + 0x40 + data1_size + data2_size, im4m, im4m_size); + // write dl payload + memcpy(*bin_out + 0x40 + data1_size + data2_size + im4m_size, uarp_fw + dl_offset, dl_size); + + // calculate CRC and update header + hdr->crc = htole32(crc_buffer(*bin_out + 0x40, content_size, 0xFFFFFFFF)); + + *bin_size = 0x40 + content_size; + + return 0; +} diff --git a/src/ace3.h b/src/ace3.h new file mode 100644 index 00000000..2ef65a7c --- /dev/null +++ b/src/ace3.h @@ -0,0 +1,17 @@ +#ifndef IDEVICERESTORE_ACE3_H +#define IDEVICERESTORE_ACE3_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, unsigned char** bin_out, size_t* bin_size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common.c b/src/common.c index 9a739940..499509d3 100644 --- a/src/common.c +++ b/src/common.c @@ -63,6 +63,7 @@ struct idevicerestore_mode_t idevicerestore_modes[] = { { 3, "Recovery" }, { 4, "Restore" }, { 5, "Normal" }, + { 6, "Port DFU" }, }; int idevicerestore_debug = 0; diff --git a/src/common.h b/src/common.h index 493b1df4..9b3c1e3b 100644 --- a/src/common.h +++ b/src/common.h @@ -47,6 +47,7 @@ extern "C" { #define _MODE_RECOVERY 3 #define _MODE_RESTORE 4 #define _MODE_NORMAL 5 +#define _MODE_PORTDFU 6 #define MODE_UNKNOWN &idevicerestore_modes[_MODE_UNKNOWN] #define MODE_WTF &idevicerestore_modes[_MODE_WTF] @@ -54,6 +55,7 @@ extern "C" { #define MODE_RECOVERY &idevicerestore_modes[_MODE_RECOVERY] #define MODE_RESTORE &idevicerestore_modes[_MODE_RESTORE] #define MODE_NORMAL &idevicerestore_modes[_MODE_NORMAL] +#define MODE_PORTDFU &idevicerestore_modes[_MODE_PORTDFU] #define FLAG_QUIT 1 diff --git a/src/dfu.c b/src/dfu.c index 8602bc0c..62a3dc09 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -118,6 +118,21 @@ int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffe return 0; } +int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size, unsigned int irecv_options) +{ + irecv_error_t err = 0; + + info("Sending data (%d bytes)...\n", size); + + err = irecv_send_buffer(client->dfu->client, buffer, size, irecv_options); + if (err != IRECV_E_SUCCESS) { + error("ERROR: Unable to send data: %s\n", irecv_strerror(err)); + return -1; + } + + return 0; +} + int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component) { char* path = NULL; @@ -204,6 +219,24 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide return 0; } +int dfu_get_bdid(struct idevicerestore_client_t* client, unsigned int* bdid) +{ + if(client->dfu == NULL) { + if (dfu_client_new(client) < 0) { + return -1; + } + } + + const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client); + if (!device_info) { + return -1; + } + + *bdid = device_info->bdid; + + return 0; +} + int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid) { if(client->dfu == NULL) { @@ -222,6 +255,27 @@ int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid) return 0; } +int dfu_get_prev(struct idevicerestore_client_t* client, unsigned int* prev) +{ + if(client->dfu == NULL) { + if (dfu_client_new(client) < 0) { + return -1; + } + } + + const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client); + if (!device_info) { + return -1; + } + char* ptr = strstr(device_info->serial_string, "PREV:"); + if (ptr) { + sscanf(ptr, "PREV:%x", prev); + return 0; + } + return -1; +} + + int dfu_is_image4_supported(struct idevicerestore_client_t* client) { if(client->dfu == NULL) { @@ -238,6 +292,35 @@ int dfu_is_image4_supported(struct idevicerestore_client_t* client) return (device_info->ibfl & IBOOT_FLAG_IMAGE4_AWARE); } +int dfu_get_portdfu_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) +{ + if(client->dfu == NULL) { + if (dfu_client_new(client) < 0) { + return -1; + } + } + + const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client); + if (!device_info) { + return -1; + } + + if (device_info->ap_nonce && device_info->ap_nonce_size > 0) { + *nonce = (unsigned char*)malloc(device_info->ap_nonce_size); + if (!*nonce) { + return -1; + } + *nonce_size = device_info->ap_nonce_size; + // The nonce is backwards, so we have to swap the bytes + unsigned int i = 0; + for (i = 0; i < *nonce_size; i++) { + (*nonce)[(*nonce_size)-1-i] = device_info->ap_nonce[i]; + } + } + + return 0; +} + int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { if(client->dfu == NULL) { diff --git a/src/dfu.h b/src/dfu.h index f6174abb..4590dbd7 100644 --- a/src/dfu.h +++ b/src/dfu.h @@ -41,9 +41,13 @@ int dfu_client_new(struct idevicerestore_client_t* client); void dfu_client_free(struct idevicerestore_client_t* client); irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client); int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size); +int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size, unsigned int irecv_options); int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component); +int dfu_get_bdid(struct idevicerestore_client_t* client, unsigned int* bdid); int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid); +int dfu_get_prev(struct idevicerestore_client_t* client, unsigned int* prev); int dfu_is_image4_supported(struct idevicerestore_client_t* client); +int dfu_get_portdfu_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity); diff --git a/src/idevicerestore.c b/src/idevicerestore.c index e71dea4e..ad02f7fd 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -47,6 +47,7 @@ #include +#include "ace3.h" #include "dfu.h" #include "tss.h" #include "img3.h" @@ -298,6 +299,9 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata) case IRECV_K_DFU_MODE: client->mode = MODE_DFU; break; + case IRECV_K_PORT_DFU_MODE: + client->mode = MODE_PORTDFU; + break; case IRECV_K_RECOVERY_MODE_1: case IRECV_K_RECOVERY_MODE_2: case IRECV_K_RECOVERY_MODE_3: @@ -316,6 +320,12 @@ static void irecv_event_cb(const irecv_device_event_t* event, void *userdata) mutex_lock(&client->device_event_mutex); client->mode = MODE_UNKNOWN; debug("%s: device %016" PRIx64 " (udid: %s) disconnected\n", __func__, client->ecid, (client->udid) ? client->udid : "N/A"); + if (event->mode == IRECV_K_PORT_DFU_MODE) { + // We have to reset the ECID here if a port DFU device disconnects, + // because when the device reconnects in a different mode, it will + // have the actual device ECID and wouldn't get detected. + client->ecid = 0; + } cond_signal(&client->device_event_cond); mutex_unlock(&client->device_event_mutex); } @@ -683,6 +693,152 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } + if (client->mode == MODE_PORTDFU) { + unsigned int pdfu_bdid = 0; + unsigned int pdfu_cpid = 0; + unsigned int prev = 0; + + if (dfu_get_bdid(client, &pdfu_bdid) < 0) { + error("ERROR: Failed to get bdid for Port DFU device!\n"); + return -1; + } + if (dfu_get_cpid(client, &pdfu_cpid) < 0) { + error("ERROR: Failed to get cpid for Port DFU device!\n"); + return -1; + } + if (dfu_get_prev(client, &prev) < 0) { + error("ERROR: Failed to get PREV for Port DFU device!\n"); + return -1; + } + + unsigned char* pdfu_nonce = NULL; + unsigned int pdfu_nsize = 0; + if (dfu_get_portdfu_nonce(client, &pdfu_nonce, &pdfu_nsize) < 0) { + error("ERROR: Failed to get nonce for Port DFU device!\n"); + return -1; + } + + plist_t build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_ERASE_INSTALL, 0); + if (!build_identity) { + error("ERORR: Failed to get build identity\n"); + return -1; + } + + unsigned int b_pdfu_cpid = (unsigned int)_plist_dict_get_uint(build_identity, "USBPortController1,ChipID"); + if (b_pdfu_cpid != pdfu_cpid) { + error("ERROR: cpid 0x%02x doesn't match USBPortController1,ChipID in build identity (0x%02x)\n", pdfu_cpid, b_pdfu_cpid); + return -1; + } + unsigned int b_pdfu_bdid = (unsigned int)_plist_dict_get_uint(build_identity, "USBPortController1,BoardID"); + if (b_pdfu_bdid != pdfu_bdid) { + error("ERROR: bdid 0x%x doesn't match USBPortController1,BoardID in build identity (0x%x)\n", pdfu_bdid, b_pdfu_bdid); + return -1; + } + + plist_t parameters = plist_new_dict(); + plist_dict_set_item(parameters, "@USBPortController1,Ticket", plist_new_bool(1)); + plist_dict_set_item(parameters, "USBPortController1,ECID", plist_new_int(client->ecid)); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); + _plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); + plist_dict_set_item(parameters, "USBPortController1,SecurityMode", plist_new_bool(1)); + plist_dict_set_item(parameters, "USBPortController1,ProductionMode", plist_new_bool(1)); + plist_t usbf = plist_access_path(build_identity, 2, "Manifest", "USBPortController1,USBFirmware"); + if (!usbf) { + plist_free(parameters); + error("ERROR: Unable to find USBPortController1,USBFirmware in build identity\n"); + return -1; + } + plist_t p_fwpath = plist_access_path(usbf, 2, "Info", "Path"); + if (!p_fwpath) { + plist_free(parameters); + error("ERROR: Unable to find path of USBPortController1,USBFirmware component\n"); + return -1; + } + const char* fwpath = plist_get_string_ptr(p_fwpath, NULL); + if (!fwpath) { + plist_free(parameters); + error("ERROR: Unable to get path of USBPortController1,USBFirmware component\n"); + return -1; + } + unsigned char* uarp_buf = NULL; + unsigned int uarp_size = 0; + if (ipsw_extract_to_memory(client->ipsw, fwpath, &uarp_buf, &uarp_size) < 0) { + plist_free(parameters); + error("ERROR: Unable to extract '%s' from IPSW\n", fwpath); + return -1; + } + usbf = plist_copy(usbf); + plist_dict_remove_item(usbf, "Info"); + plist_dict_set_item(parameters, "USBPortController1,USBFirmware", usbf); + plist_dict_set_item(parameters, "USBPortController1,Nonce", plist_new_data((const char*)pdfu_nonce, pdfu_nsize)); + + plist_t request = tss_request_new(NULL); + if (request == NULL) { + plist_free(parameters); + error("ERROR: Unable to create TSS request\n"); + return -1; + } + plist_dict_merge(&request, parameters); + plist_free(parameters); + + // send request and grab response + plist_t response = tss_request_send(request, client->tss_url); + plist_free(request); + if (response == NULL) { + error("ERROR: Unable to send TSS request\n"); + return -1; + } + info("Received USBPortController1,Ticket\n"); + + info("Creating Ace3Binary\n"); + unsigned char* ace3bin = NULL; + size_t ace3bin_size = 0; + if (ace3_create_binary(uarp_buf, uarp_size, pdfu_bdid, prev, response, &ace3bin, &ace3bin_size) < 0) { + error("ERROR: Could not create Ace3Binary\n"); + return -1; + } + plist_free(response); + free(uarp_buf); + + if (idevicerestore_keep_pers) { + write_file("Ace3Binary", (const char*)ace3bin, ace3bin_size); + } + + if (dfu_send_buffer_with_options(client, ace3bin, ace3bin_size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH | IRECV_SEND_OPT_DFU_SMALL_PKT) < 0) { + error("ERROR: Could not send Ace3Buffer to device\n"); + return -1; + } + + debug("Waiting for device to disconnect...\n"); + cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 5000); + if (client->mode != MODE_UNKNOWN || (client->flags & FLAG_QUIT)) { + mutex_unlock(&client->device_event_mutex); + + if (!(client->flags & FLAG_QUIT)) { + error("ERROR: Device did not disconnect. Port DFU failed.\n"); + } + return -2; + } + debug("Waiting for device to reconnect in DFU mode...\n"); + cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 5000); + if (client->mode != MODE_DFU || (client->flags & FLAG_QUIT)) { + mutex_unlock(&client->device_event_mutex); + if (!(client->flags & FLAG_QUIT)) { + error("ERROR: Device did not reconnect in DFU mode. Port DFU failed.\n"); + } + return -2; + } + mutex_unlock(&client->device_event_mutex); + + if (client->flags & FLAG_NOACTION) { + info("Port DFU restore successful.\n"); + return 0; + } else { + info("Port DFU restore successful. Continuing.\n"); + } + } + idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.8); /* check if device type is supported by the given build manifest */ @@ -1773,6 +1929,7 @@ irecv_device_t get_irecv_device(struct idevicerestore_client_t *client) return normal_get_irecv_device(client); case _MODE_DFU: + case _MODE_PORTDFU: case _MODE_RECOVERY: return dfu_get_irecv_device(client); From d50698e38c0e1ddfef94f7a84a34d779e4f8caba Mon Sep 17 00:00:00 2001 From: Visual Ehrmanntraut <30368284+VisualEhrmanntraut@users.noreply.github.com> Date: Wed, 3 Apr 2024 22:16:45 +0300 Subject: [PATCH 070/117] Fix restore mode component personalisation --- src/idevicerestore.c | 54 +++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index ad02f7fd..fc8b153f 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -667,14 +667,14 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } + if (client->flags & FLAG_CUSTOM) { + // prevent attempt to sign custom firmware + tss_enabled = 0; + info("Custom firmware requested; TSS has been disabled.\n"); + } + if (client->mode == MODE_RESTORE) { - if (client->flags & FLAG_ALLOW_RESTORE_MODE) { - tss_enabled = 0; - if (!client->root_ticket) { - client->root_ticket = (void*)strdup(""); - client->root_ticket_len = 0; - } - } else { + if (!(client->flags & FLAG_ALLOW_RESTORE_MODE)) { if (restore_reboot(client) < 0) { error("ERROR: Unable to exit restore mode\n"); return -2; @@ -856,12 +856,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client) client->image4supported = is_image4_supported(client); info("Device supports Image4: %s\n", (client->image4supported) ? "true" : "false"); - if (client->flags & FLAG_CUSTOM) { - /* prevent signing custom firmware */ - tss_enabled = 0; - info("Custom firmware requested. Disabled TSS request.\n"); - } - // choose whether this is an upgrade or a restore (default to upgrade) client->tss = NULL; plist_t build_identity = NULL; @@ -1241,20 +1235,34 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } - if (get_tss_response(client, build_identity, &client->tss) < 0) { - error("ERROR: Unable to get SHSH blobs for this device\n"); - return -1; - } - if (client->macos_variant) { - if (get_local_policy_tss_response(client, build_identity, &client->tss_localpolicy) < 0) { - error("ERROR: Unable to get SHSH blobs for this device (local policy)\n"); + if (client->mode == MODE_RESTORE && client->root_ticket) { + plist_t ap_ticket = plist_new_data(client->root_ticket, client->root_ticket_len); + if (!ap_ticket) { + error("ERROR: Failed to create ApImg4Ticket node value.\n"); return -1; } - if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) < - 0) { - error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n"); + client->tss = plist_new_dict(); + if (!client->tss) { + error("ERROR: Failed to create ApImg4Ticket node.\n"); + return -1; + } + plist_dict_set_item(client->tss, "ApImg4Ticket", ap_ticket); + } else { + if (get_tss_response(client, build_identity, &client->tss) < 0) { + error("ERROR: Unable to get SHSH blobs for this device\n"); return -1; } + if (client->macos_variant) { + if (get_local_policy_tss_response(client, build_identity, &client->tss_localpolicy) < 0) { + error("ERROR: Unable to get SHSH blobs for this device (local policy)\n"); + return -1; + } + if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) < + 0) { + error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n"); + return -1; + } + } } if (stashbag_commit_required) { From d8f8cb126571f1db53b7638bc2cd170716571144 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 4 Apr 2024 09:29:02 +0200 Subject: [PATCH 071/117] Remove annoying linebreak --- src/idevicerestore.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index fc8b153f..fdb340e4 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1257,8 +1257,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) error("ERROR: Unable to get SHSH blobs for this device (local policy)\n"); return -1; } - if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) < - 0) { + if (get_recoveryos_root_ticket_tss_response(client, build_identity, &client->tss_recoveryos_root_ticket) < 0) { error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n"); return -1; } From 6d40d0ab626eb0ffee4f005b7fdc915bc561deb9 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 4 Apr 2024 09:30:06 +0200 Subject: [PATCH 072/117] dfu: A little code optimization --- src/dfu.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/dfu.c b/src/dfu.c index 62a3dc09..cc8e1fbf 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -103,13 +103,13 @@ irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client) return device; } -int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size) +int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size, unsigned int irecv_options) { irecv_error_t err = 0; info("Sending data (%d bytes)...\n", size); - err = irecv_send_buffer(client->dfu->client, buffer, size, 1); + err = irecv_send_buffer(client->dfu->client, buffer, size, irecv_options); if (err != IRECV_E_SUCCESS) { error("ERROR: Unable to send data: %s\n", irecv_strerror(err)); return -1; @@ -118,19 +118,9 @@ int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffe return 0; } -int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size, unsigned int irecv_options) +int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size) { - irecv_error_t err = 0; - - info("Sending data (%d bytes)...\n", size); - - err = irecv_send_buffer(client->dfu->client, buffer, size, irecv_options); - if (err != IRECV_E_SUCCESS) { - error("ERROR: Unable to send data: %s\n", irecv_strerror(err)); - return -1; - } - - return 0; + return dfu_send_buffer_with_options(client, buffer, size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH); } int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component) @@ -208,7 +198,7 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide info("Sending %s (%d bytes)...\n", component, size); - irecv_error_t err = irecv_send_buffer(client->dfu->client, data, size, 1); + irecv_error_t err = irecv_send_buffer(client->dfu->client, data, size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH); if (err != IRECV_E_SUCCESS) { error("ERROR: Unable to send %s component: %s\n", component, irecv_strerror(err)); free(data); From 71ca0f0451c523fb47e80f53b45560e7a7b0c9b1 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 2 May 2024 19:08:20 +0200 Subject: [PATCH 073/117] [github-actions] Updated actions in build workflow --- .github/workflows/build.yml | 42 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 696dcda8..1fc2be97 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,35 +14,35 @@ jobs: run: | echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV - name: fetch libirecovery - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libirecovery-latest_${{env.target_triplet}} repo: libimobiledevice/libirecovery - name: fetch libplist - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_${{env.target_triplet}} repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_${{env.target_triplet}} repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_${{env.target_triplet}} repo: libimobiledevice/libimobiledevice-glue - name: fetch libimobiledevice - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml @@ -57,7 +57,7 @@ jobs: rm -rf extract/lib sudo cp -r extract/* / sudo ldconfig - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: autogen @@ -72,7 +72,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf idevicerestore.tar usr - name: publish artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: idevicerestore-latest_${{env.target_triplet}} path: idevicerestore.tar @@ -88,35 +88,35 @@ jobs: fi shell: bash - name: fetch libirecovery - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libirecovery-latest_macOS repo: libimobiledevice/libirecovery - name: fetch libplist - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_macOS repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_macOS repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_macOS repo: libimobiledevice/libimobiledevice-glue - name: fetch libimobiledevice - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml @@ -129,7 +129,7 @@ jobs: tar -C extract -xvf $I done sudo cp -r extract/* / - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: install additional requirements run: | SDKDIR=`xcrun --sdk macosx --show-sdk-path 2>/dev/null` @@ -182,7 +182,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf idevicerestore.tar usr - name: publish artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: idevicerestore-latest_macOS path: idevicerestore.tar @@ -219,35 +219,35 @@ jobs: echo "dest=$dest" >> $GITHUB_ENV echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV - name: fetch libirecovery - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libirecovery-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libirecovery - name: fetch libplist - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libimobiledevice-glue - name: fetch libimobiledevice - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v3 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml @@ -260,7 +260,7 @@ jobs: tar -C extract -xvf $I done cp -r extract/* / - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: install additional requirements run: | FILENAME="libzip-1.7.1-static.tar.bz2" @@ -291,7 +291,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf idevicerestore.tar ${{ env.dest }} - name: publish artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: idevicerestore-latest_${{ matrix.arch }}-${{ env.dest }} path: idevicerestore.tar From d95b43d7bef9163491f41910855e6f34bd13d88b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 2 May 2024 19:12:43 +0200 Subject: [PATCH 074/117] [github-actions] Only allow curl workflow to be triggered manually --- .github/workflows/curl.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/curl.yml b/.github/workflows/curl.yml index a2974762..87e4459b 100644 --- a/.github/workflows/curl.yml +++ b/.github/workflows/curl.yml @@ -1,6 +1,6 @@ name: build-libcurl-static -on: [push] +on: workflow_dispatch jobs: build-windows: From 0548d9f20d2937d1e122d0b405cb60219ec4fa0f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 2 May 2024 19:16:27 +0200 Subject: [PATCH 075/117] [github-actions] Fix build for macOS --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1fc2be97..76d4a0b8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -161,7 +161,7 @@ jobs: base64 -D < $FILENAME.b64 > $FILENAME tar -C deps -xjf $FILENAME echo "LIBZIP_CFLAGS=-I`pwd`/deps/include" >> $GITHUB_ENV - echo "LIBZIP_LIBS=`pwd`/deps/lib/libzip.a -Xlinker /usr/lib/libbz2.dylib -Xlinker /usr/lib/liblzma.dylib -lz" >> $GITHUB_ENV + echo "LIBZIP_LIBS=`pwd`/deps/lib/libzip.a -Xlinker ${SDKDIR}/usr/lib/libbz2.tbd -Xlinker ${SDKDIR}/usr/lib/liblzma.tbd -lz" >> $GITHUB_ENV - name: autogen run: | export CFLAGS="${{env.BUILD_CFLAGS}} -Wno-nullability-completeness -Wno-expansion-to-defined" From e6d8c0b9d53e5f3c9100cfc8c88626be45c98b85 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 5 May 2024 04:01:12 +0200 Subject: [PATCH 076/117] Updated to use libplist 2.5.0 API --- configure.ac | 2 +- src/ace3.c | 2 +- src/common.c | 139 --------------- src/common.h | 8 - src/idevicerestore.c | 56 +++---- src/img4.c | 18 +- src/normal.c | 12 +- src/restore.c | 88 +++++----- src/tss.c | 392 +++++++++++++++++++++---------------------- 9 files changed, 285 insertions(+), 432 deletions(-) diff --git a/configure.ac b/configure.ac index 1cd58444..4c39d42d 100644 --- a/configure.ac +++ b/configure.ac @@ -18,7 +18,7 @@ fi LIBIRECOVERY_VERSION=1.2.0 LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 -LIBPLIST_VERSION=2.3.0 +LIBPLIST_VERSION=2.5.0 LIMD_GLUE_VERSION=1.2.0 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 diff --git a/src/ace3.c b/src/ace3.c index b96e6b4f..d280196c 100644 --- a/src/ace3.c +++ b/src/ace3.c @@ -96,7 +96,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t plist_t p_im4m = plist_dict_get_item(tss, "USBPortController1,Ticket"); uint64_t im4m_size = 0; - const char* im4m = plist_get_data_ptr(p_im4m, &im4m_size); + const uint8_t* im4m = plist_get_data_ptr(p_im4m, &im4m_size); struct uarp_header* uarp_hdr = (struct uarp_header*)uarp_fw; uint32_t uarp_hdr_size = be32toh(uarp_hdr->header_size); diff --git a/src/common.c b/src/common.c index 499509d3..e5ee07b9 100644 --- a/src/common.c +++ b/src/common.c @@ -558,145 +558,6 @@ void get_user_input(char *buf, int maxlen, int secure) buf[len] = 0; } -uint64_t _plist_dict_get_uint(plist_t dict, const char *key) -{ - uint64_t uintval = 0; - char *strval = NULL; - uint64_t strsz = 0; - plist_t node = plist_dict_get_item(dict, key); - if (!node) { - return uintval; - } - switch (plist_get_node_type(node)) { - case PLIST_UINT: - plist_get_uint_val(node, &uintval); - break; - case PLIST_STRING: - plist_get_string_val(node, &strval); - if (strval) { - uintval = strtoull(strval, NULL, 0); - free(strval); - } - break; - case PLIST_DATA: - plist_get_data_val(node, &strval, &strsz); - if (strval) { - if (strsz == 8) { - uintval = le64toh(*(uint64_t*)strval); - } else if (strsz == 4) { - uintval = le32toh(*(uint32_t*)strval); - } else if (strsz == 2) { - uintval = le16toh(*(uint16_t*)strval); - } else if (strsz == 1) { - uintval = strval[0]; - } else { - error("%s: ERROR: invalid size %" PRIu64 " for data to integer conversion\n", __func__, strsz); - } - free(strval); - } - break; - default: - break; - } - return uintval; -} - -uint8_t _plist_dict_get_bool(plist_t dict, const char *key) -{ - uint8_t bval = 0; - uint64_t uintval = 0; - char *strval = NULL; - uint64_t strsz = 0; - plist_t node = plist_dict_get_item(dict, key); - if (!node) { - return 0; - } - switch (plist_get_node_type(node)) { - case PLIST_BOOLEAN: - plist_get_bool_val(node, &bval); - break; - case PLIST_UINT: - plist_get_uint_val(node, &uintval); - bval = (uint8_t)uintval; - break; - case PLIST_STRING: - plist_get_string_val(node, &strval); - if (strval) { - if (strcmp(strval, "true")) { - bval = 1; - } else if (strcmp(strval, "false")) { - bval = 0; - } - free(strval); - } - break; - case PLIST_DATA: - plist_get_data_val(node, &strval, &strsz); - if (strval) { - if (strsz == 1) { - bval = strval[0]; - } else { - error("%s: ERROR: invalid size %" PRIu64 " for data to boolean conversion\n", __func__, strsz); - } - free(strval); - } - break; - default: - break; - } - return bval; -} - -int _plist_dict_copy_uint(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key) -{ - if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) { - return -1; - } - uint64_t u64val = _plist_dict_get_uint(source_dict, (alt_source_key) ? alt_source_key : key); - plist_dict_set_item(target_dict, key, plist_new_uint(u64val)); - return 0; -} - -int _plist_dict_copy_bool(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key) -{ - if (plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key) == NULL) { - return -1; - } - uint64_t bval = _plist_dict_get_bool(source_dict, (alt_source_key) ? alt_source_key : key); - plist_dict_set_item(target_dict, key, plist_new_bool(bval)); - return 0; -} - -int _plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key) -{ - plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key); - if (!PLIST_IS_DATA(node)) { - return -1; - } - plist_dict_set_item(target_dict, key, plist_copy(node)); - return 0; -} - -int _plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key) -{ - plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key); - if (!PLIST_IS_STRING(node)) { - return -1; - } - plist_dict_set_item(target_dict, key, plist_copy(node)); - return 0; -} - -int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key) -{ - plist_t node = plist_dict_get_item(source_dict, (alt_source_key) ? alt_source_key : key); - if (!node) { - return -1; - } - plist_dict_set_item(target_dict, key, plist_copy(node)); - return 0; -} - const char* path_get_basename(const char* path) { #ifdef WIN32 diff --git a/src/common.h b/src/common.h index 9b3c1e3b..766a3853 100644 --- a/src/common.h +++ b/src/common.h @@ -191,14 +191,6 @@ char* realpath(const char *filename, char *resolved_name); void get_user_input(char *buf, int maxlen, int secure); -uint8_t _plist_dict_get_bool(plist_t dict, const char *key); -uint64_t _plist_dict_get_uint(plist_t dict, const char *key); -int _plist_dict_copy_uint(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); -int _plist_dict_copy_bool(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); -int _plist_dict_copy_data(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); -int _plist_dict_copy_string(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); -int _plist_dict_copy_item(plist_t target_dict, plist_t source_dict, const char *key, const char *alt_source_key); - const char* path_get_basename(const char* path); #ifdef __cplusplus diff --git a/src/idevicerestore.c b/src/idevicerestore.c index fdb340e4..ece455ed 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -724,12 +724,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) return -1; } - unsigned int b_pdfu_cpid = (unsigned int)_plist_dict_get_uint(build_identity, "USBPortController1,ChipID"); + unsigned int b_pdfu_cpid = (unsigned int)plist_dict_get_uint(build_identity, "USBPortController1,ChipID"); if (b_pdfu_cpid != pdfu_cpid) { error("ERROR: cpid 0x%02x doesn't match USBPortController1,ChipID in build identity (0x%02x)\n", pdfu_cpid, b_pdfu_cpid); return -1; } - unsigned int b_pdfu_bdid = (unsigned int)_plist_dict_get_uint(build_identity, "USBPortController1,BoardID"); + unsigned int b_pdfu_bdid = (unsigned int)plist_dict_get_uint(build_identity, "USBPortController1,BoardID"); if (b_pdfu_bdid != pdfu_bdid) { error("ERROR: bdid 0x%x doesn't match USBPortController1,BoardID in build identity (0x%x)\n", pdfu_bdid, b_pdfu_bdid); return -1; @@ -738,9 +738,9 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_t parameters = plist_new_dict(); plist_dict_set_item(parameters, "@USBPortController1,Ticket", plist_new_bool(1)); plist_dict_set_item(parameters, "USBPortController1,ECID", plist_new_int(client->ecid)); - _plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); - _plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); - _plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); + plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); + plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); + plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); plist_dict_set_item(parameters, "USBPortController1,SecurityMode", plist_new_bool(1)); plist_dict_set_item(parameters, "USBPortController1,ProductionMode", plist_new_bool(1)); plist_t usbf = plist_access_path(build_identity, 2, "Manifest", "USBPortController1,USBFirmware"); @@ -771,7 +771,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) usbf = plist_copy(usbf); plist_dict_remove_item(usbf, "Info"); plist_dict_set_item(parameters, "USBPortController1,USBFirmware", usbf); - plist_dict_set_item(parameters, "USBPortController1,Nonce", plist_new_data((const char*)pdfu_nonce, pdfu_nsize)); + plist_dict_set_item(parameters, "USBPortController1,Nonce", plist_new_data(pdfu_nonce, pdfu_nsize)); plist_t request = tss_request_new(NULL); if (request == NULL) { @@ -2263,14 +2263,14 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident plist_t parameters = plist_new_dict(); plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); if (client->nonce) { - plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); + plist_dict_set_item(parameters, "ApNonce", plist_new_data(client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data(sep_nonce, sep_nonce_size)); free(sep_nonce); } @@ -2331,20 +2331,20 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident plist_t pinfo = NULL; normal_get_preflight_info(client, &pinfo); if (pinfo) { - _plist_dict_copy_data(parameters, pinfo, "BbNonce", "Nonce"); - _plist_dict_copy_uint(parameters, pinfo, "BbChipID", "ChipID"); - _plist_dict_copy_uint(parameters, pinfo, "BbGoldCertId", "CertID"); - _plist_dict_copy_data(parameters, pinfo, "BbSNUM", "ChipSerialNo"); + plist_dict_copy_data(parameters, pinfo, "BbNonce", "Nonce"); + plist_dict_copy_uint(parameters, pinfo, "BbChipID", "ChipID"); + plist_dict_copy_uint(parameters, pinfo, "BbGoldCertId", "CertID"); + plist_dict_copy_data(parameters, pinfo, "BbSNUM", "ChipSerialNo"); /* add baseband parameters */ tss_request_add_baseband_tags(request, parameters, NULL); - _plist_dict_copy_uint(parameters, pinfo, "eUICC,ChipID", "EUICCChipID"); - if (_plist_dict_get_uint(parameters, "eUICC,ChipID") >= 5) { - _plist_dict_copy_data(parameters, pinfo, "eUICC,EID", "EUICCCSN"); - _plist_dict_copy_data(parameters, pinfo, "eUICC,RootKeyIdentifier", "EUICCCertIdentifier"); - _plist_dict_copy_data(parameters, pinfo, "EUICCGoldNonce", NULL); - _plist_dict_copy_data(parameters, pinfo, "EUICCMainNonce", NULL); + plist_dict_copy_uint(parameters, pinfo, "eUICC,ChipID", "EUICCChipID"); + if (plist_dict_get_uint(parameters, "eUICC,ChipID") >= 5) { + plist_dict_copy_data(parameters, pinfo, "eUICC,EID", "EUICCCSN"); + plist_dict_copy_data(parameters, pinfo, "eUICC,RootKeyIdentifier", "EUICCCertIdentifier"); + plist_dict_copy_data(parameters, pinfo, "EUICCGoldNonce", NULL); + plist_dict_copy_data(parameters, pinfo, "EUICCMainNonce", NULL); /* add vinyl parameters */ tss_request_add_vinyl_tags(request, parameters, NULL); @@ -2387,7 +2387,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie /* ApNonce */ if (client->nonce) { - plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); + plist_dict_set_item(parameters, "ApNonce", plist_new_data(client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; unsigned int sep_nonce_size = 0; @@ -2395,7 +2395,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie /* ApSepNonce */ if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data(sep_nonce, sep_nonce_size)); free(sep_nonce); } @@ -2496,12 +2496,12 @@ int get_recovery_os_local_policy_tss_response( uint8_t digest[SHA384_DIGEST_LENGTH]; SHA384(lpol_file, lpol_file_length, digest); plist_t lpol = plist_new_dict(); - plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); + plist_dict_set_item(lpol, "Digest", plist_new_data(digest, SHA384_DIGEST_LENGTH)); plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); plist_dict_set_item(parameters, "Ap,LocalPolicy", lpol); - _plist_dict_copy_data(parameters, args, "Ap,NextStageIM4MHash", NULL); - _plist_dict_copy_data(parameters, args, "Ap,RecoveryOSPolicyNonceHash", NULL); + plist_dict_copy_data(parameters, args, "Ap,NextStageIM4MHash", NULL); + plist_dict_copy_data(parameters, args, "Ap,RecoveryOSPolicyNonceHash", NULL); plist_t vol_uuid_node = plist_dict_get_item(args, "Ap,VolumeUUID"); char* vol_uuid_str = NULL; @@ -2518,7 +2518,7 @@ int get_recovery_os_local_policy_tss_response( for (i = 0; i < 16; i++) { vol_uuid[i] = (unsigned char)vuuid[i]; } - plist_dict_set_item(parameters, "Ap,VolumeUUID", plist_new_data((char*)vol_uuid, 16)); + plist_dict_set_item(parameters, "Ap,VolumeUUID", plist_new_data(vol_uuid, 16)); /* create basic request */ request = tss_request_new(NULL); @@ -2566,14 +2566,14 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); plist_dict_set_item(parameters, "Ap,LocalBoot", plist_new_bool(0)); if (client->nonce) { - plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); + plist_dict_set_item(parameters, "ApNonce", plist_new_data(client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data(sep_nonce, sep_nonce_size)); free(sep_nonce); } @@ -2591,7 +2591,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ uint8_t digest[SHA384_DIGEST_LENGTH]; SHA384(lpol_file, lpol_file_length, digest); plist_t lpol = plist_new_dict(); - plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); + plist_dict_set_item(lpol, "Digest", plist_new_data(digest, SHA384_DIGEST_LENGTH)); plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); plist_dict_set_item(parameters, "Ap,LocalPolicy", lpol); @@ -2603,7 +2603,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ // Hash it and add it as Ap,NextStageIM4MHash uint8_t hash[SHA384_DIGEST_LENGTH]; SHA384(ticket, ticket_length, hash); - plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_new_data((char*)hash, SHA384_DIGEST_LENGTH)); + plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_new_data(hash, SHA384_DIGEST_LENGTH)); /* create basic request */ request = tss_request_new(NULL); diff --git a/src/img4.c b/src/img4.c index 56b04964..2d1cc43a 100644 --- a/src/img4.c +++ b/src/img4.c @@ -457,7 +457,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo return -1; } uint64_t ucon_size = 0; - const char* ucon_data = plist_get_data_ptr(dt, &ucon_size); + const uint8_t* ucon_data = plist_get_data_ptr(dt, &ucon_size); if (!ucon_data) { error("ERROR: %s: Missing ucon data in %s-TBM dictionary\n", __func__, component_name); return -1; @@ -468,7 +468,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo return -1; } uint64_t ucer_size = 0; - const char* ucer_data = plist_get_data_ptr(dt, &ucer_size); + const uint8_t* ucer_data = plist_get_data_ptr(dt, &ucer_size); if (!ucer_data) { error("ERROR: %s: Missing ucer data in %s-TBM dictionary\n", __func__, component_name); return -1; @@ -705,7 +705,7 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c node = plist_dict_get_item(comp, "Digest"); if (node) { - char *digest = NULL; + uint8_t *digest = NULL; uint64_t digest_len = 0; plist_get_data_val(node, &digest, &digest_len); if (digest_len > 0) { @@ -740,7 +740,7 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c node = plist_dict_get_item(comp, "TBMDigests"); if (node) { - char *data = NULL; + uint8_t *data = NULL; uint64_t datalen = 0; plist_get_data_val(node, &data, &datalen); const char *tbmtag = NULL; @@ -798,22 +798,22 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* unsigned int tmp_len = 0; /* write manifest properties */ - uintval = _plist_dict_get_uint(request, "ApBoardID"); + uintval = plist_dict_get_uint(request, "ApBoardID"); _manifest_write_key_value(&tmp, &tmp_len, "BORD", ASN1_INTEGER, &uintval, -1); uintval = 0; _manifest_write_key_value(&tmp, &tmp_len, "CEPO", ASN1_INTEGER, &uintval, -1); - uintval = _plist_dict_get_uint(request, "ApChipID"); + uintval = plist_dict_get_uint(request, "ApChipID"); _manifest_write_key_value(&tmp, &tmp_len, "CHIP", ASN1_INTEGER, &uintval, -1); - boolval = _plist_dict_get_bool(request, "ApProductionMode"); + boolval = plist_dict_get_bool(request, "ApProductionMode"); _manifest_write_key_value(&tmp, &tmp_len, "CPRO", ASN1_BOOLEAN, &boolval, -1); boolval = 0; _manifest_write_key_value(&tmp, &tmp_len, "CSEC", ASN1_BOOLEAN, &boolval, -1); - uintval = _plist_dict_get_uint(request, "ApSecurityDomain"); + uintval = plist_dict_get_uint(request, "ApSecurityDomain"); _manifest_write_key_value(&tmp, &tmp_len, "SDOM", ASN1_INTEGER, &uintval, -1); /* create manifest properties set */ @@ -907,7 +907,7 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* length += hdr_len; - *manifest = plist_new_data((char*)buf, length); + *manifest = plist_new_data(buf, length); free(buf); diff --git a/src/normal.c b/src/normal.c index efe8f03d..8070982b 100644 --- a/src/normal.c +++ b/src/normal.c @@ -333,7 +333,7 @@ static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const } uint64_t n_size = 0; - plist_get_data_val(nonce_node, (char**)nonce, &n_size); + plist_get_data_val(nonce_node, nonce, &n_size); *nonce_size = (unsigned int)n_size; plist_free(nonce_node); @@ -462,13 +462,13 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_ } else { plist_t node; - if (_plist_dict_get_bool(pl, "Skip")) { + if (plist_dict_get_bool(pl, "Skip")) { result = 0; info("Device does not require stashbag.\n"); break; } - if (_plist_dict_get_bool(pl, "ShowDialog")) { + if (plist_dict_get_bool(pl, "ShowDialog")) { info("Device requires stashbag.\n"); printf("******************************************************************************\n" "* Please enter your passcode on the device. The device will store a token *\n" @@ -491,13 +491,13 @@ int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_ plist_free(pl); break; } - if (_plist_dict_get_bool(pl, "Timeout")) { + if (plist_dict_get_bool(pl, "Timeout")) { error("ERROR: Timeout while waiting for user to enter passcode.\n"); result = -2; plist_free(pl); break; } - if (_plist_dict_get_bool(pl, "HideDialog")) { + if (plist_dict_get_bool(pl, "HideDialog")) { plist_free(pl); /* hide dialog */ result = 1; @@ -588,7 +588,7 @@ int normal_handle_commit_stashbag(struct idevicerestore_client_t* client, plist_ } error("ERROR: Could not commit stashbag: %s\n", (strval) ? strval : "(Unknown error)"); free(strval); - } else if (_plist_dict_get_bool(pl, "StashbagCommitComplete")) { + } else if (plist_dict_get_bool(pl, "StashbagCommitComplete")) { info("Stashbag committed!\n"); result = 0; } else { diff --git a/src/restore.c b/src/restore.c index 1261147f..0e553389 100644 --- a/src/restore.c +++ b/src/restore.c @@ -976,7 +976,7 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi if (client->root_ticket) { dict = plist_new_dict(); - plist_dict_set_item(dict, "RecoveryOSRootTicketData", plist_new_data((char*)client->root_ticket, client->root_ticket_len)); + plist_dict_set_item(dict, "RecoveryOSRootTicketData", plist_new_data(client->root_ticket, client->root_ticket_len)); } else { unsigned char* data = NULL; unsigned int len = 0; @@ -1000,7 +1000,7 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi dict = plist_new_dict(); if (data && (len > 0)) { - plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len)); + plist_dict_set_item(dict, "RootTicketData", plist_new_data(data, len)); } else { info("NOTE: not sending RootTicketData (no data present)\n"); } @@ -1029,7 +1029,7 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl if (client->root_ticket) { dict = plist_new_dict(); - plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)client->root_ticket, client->root_ticket_len)); + plist_dict_set_item(dict, "RootTicketData", plist_new_data(client->root_ticket, client->root_ticket_len)); } else { unsigned char* data = NULL; unsigned int len = 0; @@ -1053,7 +1053,7 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl dict = plist_new_dict(); if (data && (len > 0)) { - plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len)); + plist_dict_set_item(dict, "RootTicketData", plist_new_data(data, len)); } else { info("NOTE: not sending RootTicketData (no data present)\n"); } @@ -1118,7 +1118,7 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie } dict = plist_new_dict(); - blob = plist_new_data((char*)data, size); + blob = plist_new_data(data, size); char compkeyname[256]; sprintf(compkeyname, "%sFile", component_name); plist_dict_set_item(dict, compkeyname, blob); @@ -1279,7 +1279,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* } dict = plist_new_dict(); - plist_dict_set_item(dict, "LlbImageData", plist_new_data((char*)llb_data, (uint64_t) llb_size)); + plist_dict_set_item(dict, "LlbImageData", plist_new_data(llb_data, llb_size)); free(llb_data); if (flash_version_1) { @@ -1339,13 +1339,13 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* component_size = 0; if (flash_version_1) { - plist_dict_set_item(norimage, component, plist_new_data((char*)nor_data, (uint64_t)nor_size)); + plist_dict_set_item(norimage, component, plist_new_data(nor_data, nor_size)); } else { /* make sure iBoot is the first entry in the array */ if (!strncmp("iBoot", component, 5)) { - plist_array_insert_item(norimage, plist_new_data((char*)nor_data, (uint64_t)nor_size), 0); + plist_array_insert_item(norimage, plist_new_data(nor_data, nor_size), 0); } else { - plist_array_append_item(norimage, plist_new_data((char*)nor_data, (uint64_t)nor_size)); + plist_array_append_item(norimage, plist_new_data(nor_data, nor_size)); } } @@ -1381,7 +1381,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* return -1; } - plist_dict_set_item(dict, "RestoreSEPImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size)); + plist_dict_set_item(dict, "RestoreSEPImageData", plist_new_data(personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; @@ -1406,7 +1406,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* return -1; } - plist_dict_set_item(dict, "SEPImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size)); + plist_dict_set_item(dict, "SEPImageData", plist_new_data(personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; @@ -1431,7 +1431,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* return -1; } - plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data((char*)personalized_data, (uint64_t) personalized_size)); + plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data(personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; @@ -1609,7 +1609,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned blob = NULL; blob_size = 0; - plist_get_data_val(node, (char**)&blob, &blob_size); + plist_get_data_val(node, &blob, &blob_size); if (!blob) { error("ERROR: could not get %s-Blob data\n", key); goto leave; @@ -1742,7 +1742,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned blob = NULL; blob_size = 0; - plist_get_data_val(bbticket, (char**)&blob, &blob_size); + plist_get_data_val(bbticket, &blob, &blob_size); if (!blob) { error("ERROR: could not get BBTicket data\n"); goto leave; @@ -1780,7 +1780,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned // add BBTicket as bbticket.der blob = NULL; blob_size = 0; - plist_get_data_val(bbticket, (char**)&blob, &blob_size); + plist_get_data_val(bbticket, &blob, &blob_size); if (!blob) { error("ERROR: could not get BBTicket data\n"); goto leave; @@ -1839,7 +1839,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer uint64_t bb_nonce_size = 0; uint64_t bb_chip_id = 0; plist_t response = NULL; - char* buffer = NULL; + uint8_t* buffer = NULL; char* bbfwtmp = NULL; plist_t dict = NULL; @@ -1860,11 +1860,11 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer } plist_t bb_snum_node = plist_dict_get_item(arguments, "ChipSerialNo"); if (bb_snum_node && plist_get_node_type(bb_snum_node) == PLIST_DATA) { - plist_get_data_val(bb_snum_node, (char**)&bb_snum, &bb_snum_size); + plist_get_data_val(bb_snum_node, &bb_snum, &bb_snum_size); } plist_t bb_nonce_node = plist_dict_get_item(arguments, "Nonce"); if (bb_nonce_node && plist_get_node_type(bb_nonce_node) == PLIST_DATA) { - plist_get_data_val(bb_nonce_node, (char**)&bb_nonce, &bb_nonce_size); + plist_get_data_val(bb_nonce_node, &bb_nonce, &bb_nonce_size); } } @@ -1873,11 +1873,11 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer plist_t parameters = plist_new_dict(); plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); if (bb_nonce) { - plist_dict_set_item(parameters, "BbNonce", plist_new_data((const char*)bb_nonce, bb_nonce_size)); + plist_dict_set_item(parameters, "BbNonce", plist_new_data(bb_nonce, bb_nonce_size)); } plist_dict_set_item(parameters, "BbChipID", plist_new_uint(bb_chip_id)); plist_dict_set_item(parameters, "BbGoldCertId", plist_new_uint(bb_cert_id)); - plist_dict_set_item(parameters, "BbSNUM", plist_new_data((const char*)bb_snum, bb_snum_size)); + plist_dict_set_item(parameters, "BbSNUM", plist_new_data(bb_snum, bb_snum_size)); tss_parameters_add_from_manifest(parameters, build_identity, true); @@ -1970,7 +1970,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer // send file dict = plist_new_dict(); - plist_dict_set_item(dict, "BasebandData", plist_new_data(buffer, (uint64_t)sz)); + plist_dict_set_item(dict, "BasebandData", plist_new_data(buffer, sz)); free(buffer); buffer = NULL; @@ -2034,7 +2034,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest int want_image_list = 0; arguments = plist_dict_get_item(message, "Arguments"); - want_image_list = _plist_dict_get_bool(arguments, image_list_k); + want_image_list = plist_dict_get_bool(arguments, image_list_k); node = plist_dict_get_item(arguments, "ImageName"); if (node) { plist_get_string_val(node, &image_name); @@ -2109,7 +2109,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest error("ERROR: Unable to get personalized component: %s\n", component); } - plist_dict_set_item(data_dict, component, plist_new_data((const char*)data, size)); + plist_dict_set_item(data_dict, component, plist_new_data(data, size)); free(data); } } @@ -2256,7 +2256,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id error("ERROR: No 'SE 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)); + plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2347,7 +2347,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc *(uint32_t*)(component_data + 4) = htole32((uint32_t)component_size); component_size += 16; - plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, (uint64_t) component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2429,7 +2429,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru comp_name = NULL; plist_t firmware_data = plist_new_dict(); - plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data((char *)component_data, (uint64_t)component_size)); + plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data(component_data, component_size)); plist_dict_set_item(response, "FirmwareData", firmware_data); free(component_data); @@ -2578,7 +2578,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct 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)); + plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2676,7 +2676,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str plist_to_bin(fw_map, &bin_plist, &bin_size); plist_free(fw_map); - plist_dict_set_item(response, "FirmwareData", plist_new_data(bin_plist, (uint64_t)bin_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((uint8_t*)bin_plist, bin_size)); free(bin_plist); return response; @@ -2798,7 +2798,7 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct return NULL; } - plist_dict_set_item(response, "FirmwareData", plist_new_data((char *)component_data, (uint64_t)component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2851,7 +2851,7 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct } else { plist_t info_dict = plist_array_get_item(info_array, 0); plist_t hwid = plist_dict_get_item(info_dict, "HardwareID"); - tag = (uint32_t)_plist_dict_get_uint(info_dict, "TagNumber"); + tag = (uint32_t)plist_dict_get_uint(info_dict, "TagNumber"); char key[64]; plist_dict_set_item(parameters, "TagNumber", plist_new_uint(tag)); @@ -2862,25 +2862,25 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct } sprintf(key, "Timer,ChipID,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "ChipID"); + plist_dict_copy_uint(parameters, hwid, key, "ChipID"); sprintf(key, "Timer,BoardID,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "BoardID"); + plist_dict_copy_uint(parameters, hwid, key, "BoardID"); sprintf(key, "Timer,ECID,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "ECID"); + plist_dict_copy_uint(parameters, hwid, key, "ECID"); sprintf(key, "Timer,Nonce,%u", tag); - _plist_dict_copy_data(parameters, hwid, key, "Nonce"); + plist_dict_copy_data(parameters, hwid, key, "Nonce"); sprintf(key, "Timer,SecurityMode,%u", tag); - _plist_dict_copy_bool(parameters, hwid, key, "SecurityMode"); + plist_dict_copy_bool(parameters, hwid, key, "SecurityMode"); sprintf(key, "Timer,SecurityDomain,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "SecurityDomain"); + plist_dict_copy_uint(parameters, hwid, key, "SecurityDomain"); sprintf(key, "Timer,ProductionMode,%u", tag); - _plist_dict_copy_uint(parameters, hwid, key, "ProductionStatus"); + plist_dict_copy_uint(parameters, hwid, key, "ProductionStatus"); } plist_t ap_info = plist_dict_get_item(p_info, "APInfo"); if (!ap_info) { @@ -2983,7 +2983,7 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct 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)); + plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -3043,10 +3043,10 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); } if (!plist_dict_get_item(parameters, "ApChipID")) { - _plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL); } if (!plist_dict_get_item(parameters, "ApBoardID")) { - _plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL); + plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL); } /* add device generated request data to parameters */ @@ -3461,7 +3461,7 @@ plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8 plist_t restore_get_build_identity_from_request(struct idevicerestore_client_t* client, plist_t msg) { plist_t args = plist_dict_get_item(msg, "Arguments"); - return restore_get_build_identity(client, _plist_dict_get_bool(args, "IsRecoveryOS")); + return restore_get_build_identity(client, plist_dict_get_bool(args, "IsRecoveryOS")); } int extract_macos_variant(plist_t build_identity, char** output) @@ -3549,7 +3549,7 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi plist_t dict = plist_new_dict(); if (data != NULL) { // Send a chunk of file data - plist_dict_set_item(dict, "FileData", plist_new_data((char*)data, size)); + plist_dict_set_item(dict, "FileData", plist_new_data(data, size)); } else { // Send FileDataDone to mark end of transfer plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); @@ -3806,7 +3806,7 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer } plist_t dict = plist_new_dict(); - plist_dict_set_item(dict, "Ap,LocalPolicy", plist_new_data((char*)data, size)); + plist_dict_set_item(dict, "Ap,LocalPolicy", plist_new_data(data, size)); int restore_error = restored_send(restore, dict); if (restore_error != RESTORE_E_SUCCESS) { @@ -4289,7 +4289,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit plist_dict_set_item(opts, "BBUpdaterState", bbus); - _plist_dict_copy_data(opts, client->preflight_info, "BasebandNonce", "Nonce"); + plist_dict_copy_data(opts, client->preflight_info, "BasebandNonce", "Nonce"); } plist_dict_set_item(opts, "SupportedDataTypes", restore_supported_data_types()); diff --git a/src/tss.c b/src/tss.c index 80591e7f..04d51087 100644 --- a/src/tss.c +++ b/src/tss.c @@ -92,39 +92,39 @@ int tss_request_add_local_policy_tags(plist_t request, plist_t parameters) { plist_dict_set_item(request, "@ApImg4Ticket", plist_new_bool(1)); - if (_plist_dict_copy_bool(request, parameters, "Ap,LocalBoot", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "Ap,LocalBoot", NULL) < 0) { error("ERROR: Unable to find required Ap,LocalBoot in parameters\n"); return -1; } - if (_plist_dict_copy_item(request, parameters, "Ap,LocalPolicy", NULL) < 0) { + if (plist_dict_copy_item(request, parameters, "Ap,LocalPolicy", NULL) < 0) { error("ERROR: Unable to find required Ap,LocalPolicy in parameters\n"); return -1; } - if (_plist_dict_copy_data(request, parameters, "Ap,NextStageIM4MHash", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "Ap,NextStageIM4MHash", NULL) < 0) { error("ERROR: Unable to find required Ap,NextStageIM4MHash in parameters\n"); return -1; } - _plist_dict_copy_data(request, parameters, "Ap,RecoveryOSPolicyNonceHash", NULL); - _plist_dict_copy_data(request, parameters, "Ap,VolumeUUID", NULL); - _plist_dict_copy_uint(request, parameters, "ApECID", NULL); - _plist_dict_copy_uint(request, parameters, "ApChipID", NULL); - _plist_dict_copy_uint(request, parameters, "ApBoardID", NULL); - _plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL); - _plist_dict_copy_data(request, parameters, "ApNonce", NULL); + plist_dict_copy_data(request, parameters, "Ap,RecoveryOSPolicyNonceHash", NULL); + plist_dict_copy_data(request, parameters, "Ap,VolumeUUID", NULL); + plist_dict_copy_uint(request, parameters, "ApECID", NULL); + plist_dict_copy_uint(request, parameters, "ApChipID", NULL); + plist_dict_copy_uint(request, parameters, "ApBoardID", NULL); + plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL); + plist_dict_copy_data(request, parameters, "ApNonce", NULL); if (!plist_dict_get_item(request, "ApSecurityMode")) { /* copy from parameters if available */ - if (_plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) { error("ERROR: Unable to find required ApSecurityMode in parameters\n"); return -1; } } if (!plist_dict_get_item(request, "ApProductionMode")) { /* copy from parameters if available */ - if (_plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { error("ERROR: Unable to find required ApProductionMode in parameters\n"); return -1; } @@ -137,121 +137,121 @@ int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, { plist_t node = NULL; - if (_plist_dict_copy_data(parameters, build_identity, "UniqueBuildID", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "UniqueBuildID", NULL) < 0) { error("ERROR: Unable to find UniqueBuildID node\n"); return -1; } - _plist_dict_copy_string(parameters, build_identity, "Ap,OSLongVersion", NULL); + plist_dict_copy_string(parameters, build_identity, "Ap,OSLongVersion", NULL); - if (_plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL) < 0) {; + if (plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL) < 0) {; error("ERROR: Unable to find ApChipID node\n"); return -1; } - if (_plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL) < 0) { + if (plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL) < 0) { error("ERROR: Unable to find ApBoardID node\n"); return -1; } - _plist_dict_copy_uint(parameters, build_identity, "ApSecurityDomain", NULL); - _plist_dict_copy_uint(parameters, build_identity, "BMU,BoardID", NULL); - _plist_dict_copy_uint(parameters, build_identity, "BMU,ChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "ApSecurityDomain", NULL); + plist_dict_copy_uint(parameters, build_identity, "BMU,BoardID", NULL); + plist_dict_copy_uint(parameters, build_identity, "BMU,ChipID", NULL); - if (_plist_dict_copy_uint(parameters, build_identity, "BbChipID", NULL) < 0) { + if (plist_dict_copy_uint(parameters, build_identity, "BbChipID", NULL) < 0) { debug("NOTE: Unable to find BbChipID node\n"); } - if (_plist_dict_copy_data(parameters, build_identity, "BbProvisioningManifestKeyHash", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "BbProvisioningManifestKeyHash", NULL) < 0) { debug("NOTE: Unable to find BbProvisioningManifestKeyHash node\n"); } - if (_plist_dict_copy_data(parameters, build_identity, "BbActivationManifestKeyHash", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "BbActivationManifestKeyHash", NULL) < 0) { debug("NOTE: Unable to find BbActivationManifestKeyHash node\n"); } - if (_plist_dict_copy_data(parameters, build_identity, "BbCalibrationManifestKeyHash", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "BbCalibrationManifestKeyHash", NULL) < 0) { debug("NOTE: Unable to find BbCalibrationManifestKeyHash node\n"); } - if (_plist_dict_copy_data(parameters, build_identity, "BbFactoryActivationManifestKeyHash", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "BbFactoryActivationManifestKeyHash", NULL) < 0) { debug("NOTE: Unable to find BbFactoryActivationManifestKeyHash node\n"); } - if (_plist_dict_copy_data(parameters, build_identity, "BbFDRSecurityKeyHash", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "BbFDRSecurityKeyHash", NULL) < 0) { debug("NOTE: Unable to find BbFDRSecurityKeyHash node\n"); } /* BbSkeyId - Used by XMM 6180/GSM */ - if (_plist_dict_copy_data(parameters, build_identity, "BbSkeyId", NULL) < 0) { + if (plist_dict_copy_data(parameters, build_identity, "BbSkeyId", NULL) < 0) { debug("NOTE: Unable to find BbSkeyId node\n"); } /* SE,ChipID - Used for SE firmware request */ - _plist_dict_copy_uint(parameters, build_identity, "SE,ChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "SE,ChipID", NULL); /* Savage,ChipID - Used for Savage firmware request */ - _plist_dict_copy_uint(parameters, build_identity, "Savage,ChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Savage,ChipID", NULL); /* add Savage,PatchEpoch - Used for Savage firmware request */ - _plist_dict_copy_uint(parameters, build_identity, "Savage,PatchEpoch", NULL); + plist_dict_copy_uint(parameters, build_identity, "Savage,PatchEpoch", NULL); /* Yonkers,BoardID - Used for Yonkers firmware request */ - _plist_dict_copy_uint(parameters, build_identity, "Yonkers,BoardID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Yonkers,BoardID", NULL); /* Yonkers,ChipID - Used for Yonkers firmware request */ - _plist_dict_copy_uint(parameters, build_identity, "Yonkers,ChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Yonkers,ChipID", NULL); /* add Yonkers,PatchEpoch - Used for Yonkers firmware request */ - _plist_dict_copy_uint(parameters, build_identity, "Yonkers,PatchEpoch", NULL); - - _plist_dict_copy_uint(parameters, build_identity, "Rap,BoardID", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Rap,ChipID", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Rap,SecurityDomain", NULL); - - _plist_dict_copy_uint(parameters, build_identity, "Baobab,BoardID", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Baobab,ChipID", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Baobab,ManifestEpoch", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Baobab,SecurityDomain", NULL); - - _plist_dict_copy_uint(parameters, build_identity, "eUICC,ChipID", NULL); - - _plist_dict_copy_uint(parameters, build_identity, "NeRDEpoch", NULL); - _plist_dict_copy_data(parameters, build_identity, "PearlCertificationRootPub", NULL); - - _plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,1", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,2", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,1", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,2", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,1", NULL); - _plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,2", NULL); - - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,ChipID", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,Type", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,SubType", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,ProductClass", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,UseProductClass", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,NonceDomain", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,Version", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,PreauthorizationVersion", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,FakeRoot", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemOS", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemVolume", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemTrustCache", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppOS", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppVolume", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppTrustCache", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainOS", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainVolume", NULL); - _plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainTrustCache", NULL); - - _plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); - _plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); - _plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); + plist_dict_copy_uint(parameters, build_identity, "Yonkers,PatchEpoch", NULL); + + plist_dict_copy_uint(parameters, build_identity, "Rap,BoardID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Rap,ChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Rap,SecurityDomain", NULL); + + plist_dict_copy_uint(parameters, build_identity, "Baobab,BoardID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Baobab,ChipID", NULL); + plist_dict_copy_uint(parameters, build_identity, "Baobab,ManifestEpoch", NULL); + plist_dict_copy_uint(parameters, build_identity, "Baobab,SecurityDomain", NULL); + + plist_dict_copy_uint(parameters, build_identity, "eUICC,ChipID", NULL); + + plist_dict_copy_uint(parameters, build_identity, "NeRDEpoch", NULL); + plist_dict_copy_data(parameters, build_identity, "PearlCertificationRootPub", NULL); + + plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,1", NULL); + plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,2", NULL); + plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,1", NULL); + plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,2", NULL); + plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,1", NULL); + plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,2", NULL); + + plist_dict_copy_item(parameters, build_identity, "Cryptex1,ChipID", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,Type", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,SubType", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,ProductClass", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,UseProductClass", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,NonceDomain", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,Version", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,PreauthorizationVersion", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,FakeRoot", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemOS", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemVolume", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemTrustCache", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppOS", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppVolume", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppTrustCache", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainOS", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainVolume", NULL); + plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainTrustCache", NULL); + + plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); + plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); + plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); node = plist_dict_get_item(build_identity, "Info"); if (node) { - _plist_dict_copy_bool(parameters, node, "RequiresUIDMode", NULL); + plist_dict_copy_bool(parameters, node, "RequiresUIDMode", NULL); } if (include_manifest) { @@ -274,9 +274,9 @@ int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) return -1; } - _plist_dict_copy_string(request, parameters, "Ap,OSLongVersion", NULL); + plist_dict_copy_string(request, parameters, "Ap,OSLongVersion", NULL); - if (_plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { error("ERROR: Unable to find required ApNonce in parameters\n"); return -1; } @@ -285,34 +285,34 @@ int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) if (!plist_dict_get_item(request, "ApSecurityMode")) { /* copy from parameters if available */ - if (_plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) { error("ERROR: Unable to find required ApSecurityMode in parameters\n"); return -1; } } if (!plist_dict_get_item(request, "ApProductionMode")) { /* ApProductionMode */ - if (_plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { error("ERROR: Unable to find required ApProductionMode in parameters\n"); return -1; } } - _plist_dict_copy_data(request, parameters, "SepNonce", "ApSepNonce"); - _plist_dict_copy_uint(request, parameters, "NeRDEpoch", NULL); - _plist_dict_copy_data(request, parameters, "PearlCertificationRootPub", NULL); + plist_dict_copy_data(request, parameters, "SepNonce", "ApSepNonce"); + plist_dict_copy_uint(request, parameters, "NeRDEpoch", NULL); + plist_dict_copy_data(request, parameters, "PearlCertificationRootPub", NULL); if (plist_dict_get_item(parameters, "UID_MODE")) { - _plist_dict_copy_item(request, parameters, "UID_MODE", NULL); - } else if (_plist_dict_get_bool(parameters, "RequiresUIDMode")) { + plist_dict_copy_item(request, parameters, "UID_MODE", NULL); + } else if (plist_dict_get_bool(parameters, "RequiresUIDMode")) { // The logic here is missing why this value is expected to be 'false' plist_dict_set_item(request, "UID_MODE", plist_new_bool(0)); } // FIXME: I didn't understand yet when this value is set, so for now we use a workaround if (plist_dict_get_item(parameters, "ApSikaFuse")) { - _plist_dict_copy_item(request, parameters, "Ap,SikaFuse", "ApSikaFuse"); - } else if (_plist_dict_get_bool(parameters, "RequiresUIDMode")) { + plist_dict_copy_item(request, parameters, "Ap,SikaFuse", "ApSikaFuse"); + } else if (plist_dict_get_bool(parameters, "RequiresUIDMode")) { // Workaround: We have only seen Ap,SikaFuse together with UID_MODE plist_dict_set_item(request, "Ap,SikaFuse", plist_new_int(0)); } @@ -327,28 +327,28 @@ int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters) return -1; } - if (_plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { error("WARNING: Unable to find ApNonce in parameters\n"); } plist_dict_set_item(request, "@APTicket", plist_new_bool(1)); - if (_plist_dict_copy_uint(request, parameters, "ApBoardID", NULL) < 0) { + if (plist_dict_copy_uint(request, parameters, "ApBoardID", NULL) < 0) { error("ERROR: Unable to find required ApBoardID in request\n"); return -1; } - if (_plist_dict_copy_uint(request, parameters, "ApChipID", NULL) < 0) { + if (plist_dict_copy_uint(request, parameters, "ApChipID", NULL) < 0) { error("ERROR: Unable to find required ApChipID in request\n"); return -1; } - if (_plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL) < 0) { + if (plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL) < 0) { error("ERROR: Unable to find required ApSecurityDomain in request\n"); return -1; } - if (_plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { error("ERROR: Unable to find required ApProductionMode in parameters\n"); return -1; } @@ -358,11 +358,11 @@ int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters) int tss_request_add_common_tags(plist_t request, plist_t parameters, plist_t overrides) { - _plist_dict_copy_uint(request, parameters, "ApECID", NULL); - _plist_dict_copy_data(request, parameters, "UniqueBuildID", NULL); - _plist_dict_copy_uint(request, parameters, "ApChipID", NULL); - _plist_dict_copy_uint(request, parameters, "ApBoardID", NULL); - _plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL); + plist_dict_copy_uint(request, parameters, "ApECID", NULL); + plist_dict_copy_data(request, parameters, "UniqueBuildID", NULL); + plist_dict_copy_uint(request, parameters, "ApChipID", NULL); + plist_dict_copy_uint(request, parameters, "ApBoardID", NULL); + plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL); /* apply overrides */ if (overrides) { @@ -576,19 +576,19 @@ int tss_request_add_ap_recovery_tags(plist_t request, plist_t parameters, plist_ continue; } - if (_plist_dict_get_bool(parameters, "_OnlyFWComponents")) { - if (!_plist_dict_get_bool(manifest_entry, "Trusted")) { + if (plist_dict_get_bool(parameters, "_OnlyFWComponents")) { + if (!plist_dict_get_bool(manifest_entry, "Trusted")) { debug("DEBUG: %s: Skipping '%s' as it is not trusted\n", __func__, key); continue; } - if (!_plist_dict_get_bool(info_dict, "IsFirmwarePayload") - && !_plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") - && !_plist_dict_get_bool(info_dict, "IsFUDFirmware") - && !_plist_dict_get_bool(info_dict, "IsLoadedByiBoot") - && !_plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") - && !_plist_dict_get_bool(info_dict, "IsiBootEANFirmware") - && !_plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware")) + if (!plist_dict_get_bool(info_dict, "IsFirmwarePayload") + && !plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") + && !plist_dict_get_bool(info_dict, "IsFUDFirmware") + && !plist_dict_get_bool(info_dict, "IsLoadedByiBoot") + && !plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") + && !plist_dict_get_bool(info_dict, "IsiBootEANFirmware") + && !plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware")) { debug("DEBUG: %s: Skipping '%s' as it is not a firmware payload\n", __func__, key); continue; @@ -609,7 +609,7 @@ int tss_request_add_ap_recovery_tags(plist_t request, plist_t parameters, plist_ } /* Make sure we have a Digest key for Trusted items even if empty */ - if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { + if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { debug("DEBUG: No Digest data, using empty value for entry %s\n", key); plist_dict_set_item(tss_entry, "Digest", plist_new_data(NULL, 0)); } @@ -679,28 +679,28 @@ int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrid continue; } - if (_plist_dict_get_bool(parameters, "ApSupportsImg4")) { + if (plist_dict_get_bool(parameters, "ApSupportsImg4")) { if (!plist_dict_get_item(info_dict, "RestoreRequestRules")) { debug("DEBUG: %s: Skipping '%s' as it doesn't have RestoreRequestRules\n", __func__, key); continue; } } - int is_fw_payload = _plist_dict_get_bool(info_dict, "IsFirmwarePayload") - || _plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") - || _plist_dict_get_bool(info_dict, "IsFUDFirmware") - || _plist_dict_get_bool(info_dict, "IsLoadedByiBoot") - || _plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") - || _plist_dict_get_bool(info_dict, "IsiBootEANFirmware") - || _plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware"); + int is_fw_payload = plist_dict_get_bool(info_dict, "IsFirmwarePayload") + || plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") + || plist_dict_get_bool(info_dict, "IsFUDFirmware") + || plist_dict_get_bool(info_dict, "IsLoadedByiBoot") + || plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") + || plist_dict_get_bool(info_dict, "IsiBootEANFirmware") + || plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware"); - if (_plist_dict_get_bool(parameters, "_OnlyFWOrTrustedComponents")) { - if (!_plist_dict_get_bool(manifest_entry, "Trusted") && !is_fw_payload) { + if (plist_dict_get_bool(parameters, "_OnlyFWOrTrustedComponents")) { + if (!plist_dict_get_bool(manifest_entry, "Trusted") && !is_fw_payload) { debug("DEBUG: %s: Skipping '%s' as it is neither firmware payload nor trusted\n", __func__, key); continue; } - } else if (_plist_dict_get_bool(parameters, "_OnlyFWComponents")) { - if (!_plist_dict_get_bool(manifest_entry, "Trusted")) { + } else if (plist_dict_get_bool(parameters, "_OnlyFWComponents")) { + if (!plist_dict_get_bool(manifest_entry, "Trusted")) { debug("DEBUG: %s: Skipping '%s' as it is not trusted\n", __func__, key); continue; } @@ -711,7 +711,7 @@ int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrid } /* skip components with IsFTAB:true */ - if (_plist_dict_get_bool(info_dict, "IsFTAB")) { + if (plist_dict_get_bool(info_dict, "IsFTAB")) { debug("DEBUG: %s: Skipping FTAB component '%s'\n", __func__, key); continue; } @@ -730,7 +730,7 @@ int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrid } /* Make sure we have a Digest key for Trusted items even if empty */ - if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { + if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { debug("DEBUG: No Digest data, using empty value for entry %s\n", key); plist_dict_set_item(tss_entry, "Digest", plist_new_data(NULL, 0)); } @@ -755,22 +755,22 @@ int tss_request_add_baseband_tags(plist_t request, plist_t parameters, plist_t o plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - _plist_dict_copy_uint(request, parameters, "BbChipID", NULL); - _plist_dict_copy_data(request, parameters, "BbProvisioningManifestKeyHash", NULL); + plist_dict_copy_uint(request, parameters, "BbChipID", NULL); + plist_dict_copy_data(request, parameters, "BbProvisioningManifestKeyHash", NULL); /* BbActivationManifestKeyHash - Used by Qualcomm MDM6610 */ - _plist_dict_copy_data(request, parameters, "BbActivationManifestKeyHash", NULL); - _plist_dict_copy_data(request, parameters, "BbCalibrationManifestKeyHash", NULL); - _plist_dict_copy_data(request, parameters, "BbFactoryActivationManifestKeyHash", NULL); - _plist_dict_copy_data(request, parameters, "BbFDRSecurityKeyHash", NULL); + plist_dict_copy_data(request, parameters, "BbActivationManifestKeyHash", NULL); + plist_dict_copy_data(request, parameters, "BbCalibrationManifestKeyHash", NULL); + plist_dict_copy_data(request, parameters, "BbFactoryActivationManifestKeyHash", NULL); + plist_dict_copy_data(request, parameters, "BbFDRSecurityKeyHash", NULL); /* BbSkeyId - Used by XMM 6180/GSM */ - _plist_dict_copy_data(request, parameters, "BbSkeyId", NULL); - _plist_dict_copy_data(request, parameters, "BbNonce", NULL); - _plist_dict_copy_uint(request, parameters, "BbGoldCertId", NULL); + plist_dict_copy_data(request, parameters, "BbSkeyId", NULL); + plist_dict_copy_data(request, parameters, "BbNonce", NULL); + plist_dict_copy_uint(request, parameters, "BbGoldCertId", NULL); - uint64_t bb_chip_id = _plist_dict_get_uint(request, "BbChipID"); - int32_t bb_cert_id = (int32_t)_plist_dict_get_uint(request, "BbGoldCertId"); + uint64_t bb_chip_id = plist_dict_get_uint(request, "BbChipID"); + int32_t bb_cert_id = (int32_t)plist_dict_get_uint(request, "BbGoldCertId"); - if (_plist_dict_copy_data(request, parameters, "BbSNUM", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "BbSNUM", NULL) < 0) { error("ERROR: Unable to find required BbSNUM in parameters\n"); return -1; } @@ -818,28 +818,28 @@ int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrid plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - if (_plist_dict_copy_uint(request, parameters, "SE,ChipID", NULL) < 0) { + if (plist_dict_copy_uint(request, parameters, "SE,ChipID", NULL) < 0) { error("ERROR: %s: Unable to find required SE,ChipID in parameters\n", __func__); return -1; } - if (_plist_dict_copy_data(request, parameters, "SE,ID", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "SE,ID", NULL) < 0) { error("ERROR: %s: Unable to find required SE,ID in parameters\n", __func__); return -1; } - if (_plist_dict_copy_data(request, parameters, "SE,Nonce", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "SE,Nonce", NULL) < 0) { error("ERROR: %s: Unable to find required SE,Nonce in parameters\n", __func__); return -1; } - if (_plist_dict_copy_data(request, parameters, "SE,RootKeyIdentifier", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "SE,RootKeyIdentifier", NULL) < 0) { error("ERROR: %s: Unable to find required SE,RootKeyIdentifier in parameters\n", __func__); return -1; } /* 'IsDev' determines whether we have Production or Development */ - uint8_t is_dev = _plist_dict_get_bool(parameters, "SE,IsDev"); + uint8_t is_dev = plist_dict_get_bool(parameters, "SE,IsDev"); /* add SE,* components from build manifest to request */ char* key = NULL; @@ -914,7 +914,7 @@ int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t ove plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@Savage,Ticket", plist_new_bool(1)); - if (_plist_dict_copy_data(request, parameters, "Savage,UID", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "Savage,UID", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,UID in parameters\n", __func__); return -1; } @@ -929,33 +929,33 @@ int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t ove plist_dict_set_item(dict, "Digest", plist_copy(node)); plist_dict_set_item(request, "SEP", dict); - if (_plist_dict_copy_uint(request, parameters, "Savage,PatchEpoch", NULL) < 0) { + if (plist_dict_copy_uint(request, parameters, "Savage,PatchEpoch", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,PatchEpoch in parameters\n", __func__); return -1; } - if (_plist_dict_copy_uint(request, parameters, "Savage,ChipID", NULL) < 0) { + if (plist_dict_copy_uint(request, parameters, "Savage,ChipID", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,ChipID in parameters\n", __func__); return -1; } - if (_plist_dict_copy_bool(request, parameters, "Savage,AllowOfflineBoot", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "Savage,AllowOfflineBoot", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,AllowOfflineBoot in parameters\n", __func__); return -1; } - if (_plist_dict_copy_bool(request, parameters, "Savage,ReadFWKey", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "Savage,ReadFWKey", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,ReadFWKey in parameters\n", __func__); return -1; } - if (_plist_dict_copy_bool(request, parameters, "Savage,ProductionMode", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "Savage,ProductionMode", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,ProductionMode in parameters\n", __func__); return -1; } const char *comp_name = NULL; - uint8_t isprod = _plist_dict_get_bool(request, "Savage,ProductionMode"); + uint8_t isprod = plist_dict_get_bool(request, "Savage,ProductionMode"); /* get the right component name */ comp_name = (isprod) ? "Savage,B0-Prod-Patch" : "Savage,B0-Dev-Patch"; @@ -963,7 +963,7 @@ int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t ove if (node && (plist_get_node_type(node) == PLIST_DATA)) { unsigned char *savage_rev = NULL; uint64_t savage_rev_len = 0; - plist_get_data_val(node, (char**)&savage_rev, &savage_rev_len); + plist_get_data_val(node, &savage_rev, &savage_rev_len); if (savage_rev_len > 0) { if (((savage_rev[0] | 0x10) & 0xF0) == 0x30) { comp_name = (isprod) ? "Savage,B2-Prod-Patch" : "Savage,B2-Dev-Patch"; @@ -988,12 +988,12 @@ int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t ove *component_name = strdup(comp_name); } - if (_plist_dict_copy_data(request, parameters, "Savage,Nonce", NULL) < 0) { + if (plist_dict_copy_data(request, parameters, "Savage,Nonce", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,Nonce in parameters\n", __func__); return -1; } - if (_plist_dict_copy_bool(request, parameters, "Savage,ReadECKey", NULL) < 0) { + if (plist_dict_copy_bool(request, parameters, "Savage,ReadECKey", NULL) < 0) { error("ERROR: %s: Unable to find required Savage,ReadECKey in parameters\n", __func__); return -1; } @@ -1045,8 +1045,8 @@ int tss_request_add_yonkers_tags(plist_t request, plist_t parameters, plist_t ov char *comp_name = NULL; plist_t comp_node = NULL; - uint8_t isprod = _plist_dict_get_bool(parameters, "Yonkers,ProductionMode"); - uint64_t fabrevision = _plist_dict_get_uint(parameters, "Yonkers,FabRevision"); + uint8_t isprod = plist_dict_get_bool(parameters, "Yonkers,ProductionMode"); + uint64_t fabrevision = plist_dict_get_uint(parameters, "Yonkers,FabRevision"); plist_dict_iter iter = NULL; plist_dict_new_iter(manifest_node, &iter); @@ -1120,16 +1120,16 @@ int tss_request_add_vinyl_tags(plist_t request, plist_t parameters, plist_t over plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@eUICC,Ticket", plist_new_bool(1)); - _plist_dict_copy_bool(request, parameters, "eUICC,ApProductionMode", "ApProductionMode"); - _plist_dict_copy_uint(request, parameters, "eUICC,ChipID", NULL); - _plist_dict_copy_data(request, parameters, "eUICC,EID", NULL); - _plist_dict_copy_data(request, parameters, "eUICC,RootKeyIdentifier", NULL); + plist_dict_copy_bool(request, parameters, "eUICC,ApProductionMode", "ApProductionMode"); + plist_dict_copy_uint(request, parameters, "eUICC,ChipID", NULL); + plist_dict_copy_data(request, parameters, "eUICC,EID", NULL); + plist_dict_copy_data(request, parameters, "eUICC,RootKeyIdentifier", NULL); if (!plist_dict_get_item(request, "eUICC,Gold")) { plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Gold"); if (n) { plist_t p = plist_new_dict(); - _plist_dict_copy_data(p, n, "Digest", NULL); + plist_dict_copy_data(p, n, "Digest", NULL); plist_dict_set_item(request, "eUICC,Gold", p); } } @@ -1138,7 +1138,7 @@ int tss_request_add_vinyl_tags(plist_t request, plist_t parameters, plist_t over plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Main"); if (n) { plist_t p = plist_new_dict(); - _plist_dict_copy_data(p, n, "Digest", NULL); + plist_dict_copy_data(p, n, "Digest", NULL); plist_dict_set_item(request, "eUICC,Main", p); } } @@ -1183,14 +1183,14 @@ int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overr plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@Rap,Ticket", plist_new_bool(1)); - _plist_dict_copy_uint(request, parameters, "Rap,BoardID", NULL); - _plist_dict_copy_uint(request, parameters, "Rap,ChipID", NULL); - _plist_dict_copy_uint(request, parameters, "Rap,ECID", NULL); - _plist_dict_copy_data(request, parameters, "Rap,Nonce", NULL); - _plist_dict_copy_bool(request, parameters, "Rap,ProductionMode", NULL); - _plist_dict_copy_uint(request, parameters, "Rap,SecurityDomain", NULL); - _plist_dict_copy_bool(request, parameters, "Rap,SecurityMode", NULL); - _plist_dict_copy_data(request, parameters, "Rap,FdrRootCaDigest", NULL); + plist_dict_copy_uint(request, parameters, "Rap,BoardID", NULL); + plist_dict_copy_uint(request, parameters, "Rap,ChipID", NULL); + plist_dict_copy_uint(request, parameters, "Rap,ECID", NULL); + plist_dict_copy_data(request, parameters, "Rap,Nonce", NULL); + plist_dict_copy_bool(request, parameters, "Rap,ProductionMode", NULL); + plist_dict_copy_uint(request, parameters, "Rap,SecurityDomain", NULL); + plist_dict_copy_bool(request, parameters, "Rap,SecurityMode", NULL); + plist_dict_copy_data(request, parameters, "Rap,FdrRootCaDigest", NULL); char *comp_name = NULL; plist_dict_iter iter = NULL; @@ -1214,7 +1214,7 @@ int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overr } /* Make sure we have a Digest key for Trusted items even if empty */ - if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { + if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "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)); } @@ -1250,11 +1250,11 @@ int tss_request_add_veridian_tags(plist_t request, plist_t parameters, plist_t o plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@BMU,Ticket", plist_new_bool(1)); - _plist_dict_copy_uint(request, parameters, "BMU,BoardID", NULL); - _plist_dict_copy_uint(request, parameters, "BMU,ChipID", "ChipID"); - _plist_dict_copy_data(request, parameters, "BMU,Nonce", "Nonce"); - _plist_dict_copy_bool(request, parameters, "BMU,ProductionMode", "ProductionMode"); - _plist_dict_copy_uint(request, parameters, "BMU,UniqueID", "UniqueID"); + plist_dict_copy_uint(request, parameters, "BMU,BoardID", NULL); + plist_dict_copy_uint(request, parameters, "BMU,ChipID", "ChipID"); + plist_dict_copy_data(request, parameters, "BMU,Nonce", "Nonce"); + plist_dict_copy_bool(request, parameters, "BMU,ProductionMode", "ProductionMode"); + plist_dict_copy_uint(request, parameters, "BMU,UniqueID", "UniqueID"); char *comp_name = NULL; plist_dict_iter iter = NULL; @@ -1278,7 +1278,7 @@ int tss_request_add_veridian_tags(plist_t request, plist_t parameters, plist_t o } /* Make sure we have a Digest key for Trusted items even if empty */ - if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { + if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "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)); } @@ -1314,16 +1314,16 @@ int tss_request_add_tcon_tags(plist_t request, plist_t parameters, plist_t overr plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); plist_dict_set_item(request, "@Baobab,Ticket", plist_new_bool(1)); - _plist_dict_copy_uint(request, parameters, "Baobab,BoardID", NULL); - _plist_dict_copy_uint(request, parameters, "Baobab,ChipID", NULL); - _plist_dict_copy_data(request, parameters, "Baobab,ECID", NULL); - _plist_dict_copy_uint(request, parameters, "Baobab,Life", NULL); - _plist_dict_copy_uint(request, parameters, "Baobab,ManifestEpoch", NULL); - _plist_dict_copy_bool(request, parameters, "Baobab,ProductionMode", NULL); - _plist_dict_copy_uint(request, parameters, "Baobab,SecurityDomain", NULL); - _plist_dict_copy_data(request, parameters, "Baobab,UpdateNonce", NULL); + plist_dict_copy_uint(request, parameters, "Baobab,BoardID", NULL); + plist_dict_copy_uint(request, parameters, "Baobab,ChipID", NULL); + plist_dict_copy_data(request, parameters, "Baobab,ECID", NULL); + plist_dict_copy_uint(request, parameters, "Baobab,Life", NULL); + plist_dict_copy_uint(request, parameters, "Baobab,ManifestEpoch", NULL); + plist_dict_copy_bool(request, parameters, "Baobab,ProductionMode", NULL); + plist_dict_copy_uint(request, parameters, "Baobab,SecurityDomain", NULL); + plist_dict_copy_data(request, parameters, "Baobab,UpdateNonce", NULL); - uint8_t isprod = _plist_dict_get_bool(parameters, "Baobab,ProductionMode"); + uint8_t isprod = plist_dict_get_bool(parameters, "Baobab,ProductionMode"); char *comp_name = NULL; plist_dict_iter iter = NULL; @@ -1380,28 +1380,28 @@ int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t over plist_dict_set_item(request, key, plist_new_bool(1)); - tag = (uint32_t)_plist_dict_get_uint(parameters, "TagNumber"); + tag = (uint32_t)plist_dict_get_uint(parameters, "TagNumber"); sprintf(key, "Timer,BoardID,%u", tag); - _plist_dict_copy_uint(request, parameters, key, NULL); + plist_dict_copy_uint(request, parameters, key, NULL); sprintf(key, "Timer,ChipID,%u", tag); - _plist_dict_copy_uint(request, parameters, key, NULL); + plist_dict_copy_uint(request, parameters, key, NULL); sprintf(key, "Timer,SecurityDomain,%u", tag); - _plist_dict_copy_uint(request, parameters, key, NULL); + plist_dict_copy_uint(request, parameters, key, NULL); sprintf(key, "Timer,SecurityMode,%u", tag); - _plist_dict_copy_bool(request, parameters, key, NULL); + plist_dict_copy_bool(request, parameters, key, NULL); sprintf(key, "Timer,ProductionMode,%u", tag); - _plist_dict_copy_bool(request, parameters, key, NULL); + plist_dict_copy_bool(request, parameters, key, NULL); sprintf(key, "Timer,ECID,%u", tag); - _plist_dict_copy_uint(request, parameters, key, NULL); + plist_dict_copy_uint(request, parameters, key, NULL); sprintf(key, "Timer,Nonce,%u", tag); - _plist_dict_copy_data(request, parameters, key, NULL); + plist_dict_copy_data(request, parameters, key, NULL); char *comp_name = NULL; plist_dict_iter iter = NULL; @@ -1425,7 +1425,7 @@ int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t over } /* Make sure we have a Digest key for Trusted items even if empty */ - if (_plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { + if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "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)); } @@ -1454,13 +1454,13 @@ int tss_request_add_cryptex_tags(plist_t request, plist_t parameters, plist_t ov if (plist_dict_get_item(parameters, "Ap,LocalPolicy")) { /* Cryptex1LocalPolicy */ tss_request_add_local_policy_tags(request, parameters); - _plist_dict_copy_data(request, parameters, "Ap,NextStageCryptex1IM4MHash", NULL); + plist_dict_copy_data(request, parameters, "Ap,NextStageCryptex1IM4MHash", NULL); } else { /* Cryptex1 */ plist_dict_set_item(request, "@Cryptex1,Ticket", plist_new_bool(1)); - _plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL); - _plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL); + plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL); + plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL); plist_dict_iter iter = NULL; plist_dict_new_iter(parameters, &iter); @@ -1659,7 +1659,7 @@ static int tss_response_get_data_by_key(plist_t response, const char* name, unsi return -1; } - char *data = NULL; + uint8_t* data = NULL; uint64_t len = 0; plist_get_data_val(node, &data, &len); if (data) { @@ -1718,7 +1718,7 @@ int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char** uint32_t tss_size = 0; uint64_t blob_size = 0; char* entry_key = NULL; - char* blob_data = NULL; + uint8_t* blob_data = NULL; char* entry_path = NULL; plist_t tss_entry = NULL; plist_t blob_node = NULL; @@ -1772,7 +1772,7 @@ int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char** int tss_response_get_blob_by_entry(plist_t response, const char* entry, unsigned char** blob) { uint64_t blob_size = 0; - char* blob_data = NULL; + uint8_t* blob_data = NULL; plist_t blob_node = NULL; plist_t tss_entry = NULL; From 653349a1eac8c52776dcfd17cb82bbeac272fb71 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 14 May 2024 09:36:42 +0200 Subject: [PATCH 077/117] Require libplist 2.6.0 --- configure.ac | 2 +- src/ace3.c | 2 +- src/idevicerestore.c | 24 +++++++-------- src/img4.c | 18 +++++------ src/restore.c | 73 +++++++++++++++++++------------------------- src/tss.c | 10 +++--- 6 files changed, 57 insertions(+), 72 deletions(-) diff --git a/configure.ac b/configure.ac index 4c39d42d..0b5fcea2 100644 --- a/configure.ac +++ b/configure.ac @@ -18,7 +18,7 @@ fi LIBIRECOVERY_VERSION=1.2.0 LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 -LIBPLIST_VERSION=2.5.0 +LIBPLIST_VERSION=2.6.0 LIMD_GLUE_VERSION=1.2.0 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 diff --git a/src/ace3.c b/src/ace3.c index d280196c..b96e6b4f 100644 --- a/src/ace3.c +++ b/src/ace3.c @@ -96,7 +96,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t plist_t p_im4m = plist_dict_get_item(tss, "USBPortController1,Ticket"); uint64_t im4m_size = 0; - const uint8_t* im4m = plist_get_data_ptr(p_im4m, &im4m_size); + const char* im4m = plist_get_data_ptr(p_im4m, &im4m_size); struct uarp_header* uarp_hdr = (struct uarp_header*)uarp_fw; uint32_t uarp_hdr_size = be32toh(uarp_hdr->header_size); diff --git a/src/idevicerestore.c b/src/idevicerestore.c index ece455ed..f27c3572 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -771,7 +771,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) usbf = plist_copy(usbf); plist_dict_remove_item(usbf, "Info"); plist_dict_set_item(parameters, "USBPortController1,USBFirmware", usbf); - plist_dict_set_item(parameters, "USBPortController1,Nonce", plist_new_data(pdfu_nonce, pdfu_nsize)); + plist_dict_set_item(parameters, "USBPortController1,Nonce", plist_new_data((const char*)pdfu_nonce, pdfu_nsize)); plist_t request = tss_request_new(NULL); if (request == NULL) { @@ -1236,7 +1236,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } if (client->mode == MODE_RESTORE && client->root_ticket) { - plist_t ap_ticket = plist_new_data(client->root_ticket, client->root_ticket_len); + plist_t ap_ticket = plist_new_data((char*)client->root_ticket, client->root_ticket_len); if (!ap_ticket) { error("ERROR: Failed to create ApImg4Ticket node value.\n"); return -1; @@ -2263,14 +2263,14 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident plist_t parameters = plist_new_dict(); plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); if (client->nonce) { - plist_dict_set_item(parameters, "ApNonce", plist_new_data(client->nonce, client->nonce_size)); + plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data(sep_nonce, sep_nonce_size)); + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); free(sep_nonce); } @@ -2387,7 +2387,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie /* ApNonce */ if (client->nonce) { - plist_dict_set_item(parameters, "ApNonce", plist_new_data(client->nonce, client->nonce_size)); + plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; unsigned int sep_nonce_size = 0; @@ -2395,7 +2395,7 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie /* ApSepNonce */ if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data(sep_nonce, sep_nonce_size)); + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); free(sep_nonce); } @@ -2496,7 +2496,7 @@ int get_recovery_os_local_policy_tss_response( uint8_t digest[SHA384_DIGEST_LENGTH]; SHA384(lpol_file, lpol_file_length, digest); plist_t lpol = plist_new_dict(); - plist_dict_set_item(lpol, "Digest", plist_new_data(digest, SHA384_DIGEST_LENGTH)); + plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); plist_dict_set_item(parameters, "Ap,LocalPolicy", lpol); @@ -2518,7 +2518,7 @@ int get_recovery_os_local_policy_tss_response( for (i = 0; i < 16; i++) { vol_uuid[i] = (unsigned char)vuuid[i]; } - plist_dict_set_item(parameters, "Ap,VolumeUUID", plist_new_data(vol_uuid, 16)); + plist_dict_set_item(parameters, "Ap,VolumeUUID", plist_new_data((char*)vol_uuid, 16)); /* create basic request */ request = tss_request_new(NULL); @@ -2566,14 +2566,14 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); plist_dict_set_item(parameters, "Ap,LocalBoot", plist_new_bool(0)); if (client->nonce) { - plist_dict_set_item(parameters, "ApNonce", plist_new_data(client->nonce, client->nonce_size)); + plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } unsigned char* sep_nonce = NULL; unsigned int sep_nonce_size = 0; get_sep_nonce(client, &sep_nonce, &sep_nonce_size); if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data(sep_nonce, sep_nonce_size)); + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); free(sep_nonce); } @@ -2591,7 +2591,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ uint8_t digest[SHA384_DIGEST_LENGTH]; SHA384(lpol_file, lpol_file_length, digest); plist_t lpol = plist_new_dict(); - plist_dict_set_item(lpol, "Digest", plist_new_data(digest, SHA384_DIGEST_LENGTH)); + plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); plist_dict_set_item(parameters, "Ap,LocalPolicy", lpol); @@ -2603,7 +2603,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ // Hash it and add it as Ap,NextStageIM4MHash uint8_t hash[SHA384_DIGEST_LENGTH]; SHA384(ticket, ticket_length, hash); - plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_new_data(hash, SHA384_DIGEST_LENGTH)); + plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_new_data((char*)hash, SHA384_DIGEST_LENGTH)); /* create basic request */ request = tss_request_new(NULL); diff --git a/src/img4.c b/src/img4.c index 2d1cc43a..9a0cb29f 100644 --- a/src/img4.c +++ b/src/img4.c @@ -457,7 +457,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo return -1; } uint64_t ucon_size = 0; - const uint8_t* ucon_data = plist_get_data_ptr(dt, &ucon_size); + const char* ucon_data = plist_get_data_ptr(dt, &ucon_size); if (!ucon_data) { error("ERROR: %s: Missing ucon data in %s-TBM dictionary\n", __func__, component_name); return -1; @@ -468,7 +468,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo return -1; } uint64_t ucer_size = 0; - const uint8_t* ucer_data = plist_get_data_ptr(dt, &ucer_size); + const char* ucer_data = plist_get_data_ptr(dt, &ucer_size); if (!ucer_data) { error("ERROR: %s: Missing ucer data in %s-TBM dictionary\n", __func__, component_name); return -1; @@ -705,13 +705,11 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c node = plist_dict_get_item(comp, "Digest"); if (node) { - uint8_t *digest = NULL; uint64_t digest_len = 0; - plist_get_data_val(node, &digest, &digest_len); + const char *digest = plist_get_data_ptr(node, &digest_len); if (digest_len > 0) { - _manifest_write_key_value(&tmp, &tmp_len, "DGST", ASN1_OCTET_STRING, digest, digest_len); + _manifest_write_key_value(&tmp, &tmp_len, "DGST", ASN1_OCTET_STRING, (void*)digest, digest_len); } - free(digest); } node = plist_dict_get_item(comp, "Trusted"); @@ -740,9 +738,8 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c node = plist_dict_get_item(comp, "TBMDigests"); if (node) { - uint8_t *data = NULL; uint64_t datalen = 0; - plist_get_data_val(node, &data, &datalen); + const char *data = plist_get_data_ptr(node, &datalen); const char *tbmtag = NULL; if (!strcmp(tag, "sepi")) { tbmtag = "tbms"; @@ -752,9 +749,8 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c if (!tbmtag) { error("ERROR: Unexpected TMBDigests for comp '%s'\n", tag); } else { - _manifest_write_key_value(&tmp, &tmp_len, tbmtag, ASN1_OCTET_STRING, data, datalen); + _manifest_write_key_value(&tmp, &tmp_len, tbmtag, ASN1_OCTET_STRING, (void*)data, datalen); } - free(data); } asn1_write_element_header(ASN1_SET | ASN1_CONSTRUCTED, tmp_len, &inner_start, &inner_length); @@ -907,7 +903,7 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* length += hdr_len; - *manifest = plist_new_data(buf, length); + *manifest = plist_new_data((char*)buf, length); free(buf); diff --git a/src/restore.c b/src/restore.c index 0e553389..050ee3b2 100644 --- a/src/restore.c +++ b/src/restore.c @@ -976,7 +976,7 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi if (client->root_ticket) { dict = plist_new_dict(); - plist_dict_set_item(dict, "RecoveryOSRootTicketData", plist_new_data(client->root_ticket, client->root_ticket_len)); + plist_dict_set_item(dict, "RecoveryOSRootTicketData", plist_new_data((char*)client->root_ticket, client->root_ticket_len)); } else { unsigned char* data = NULL; unsigned int len = 0; @@ -1000,7 +1000,7 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi dict = plist_new_dict(); if (data && (len > 0)) { - plist_dict_set_item(dict, "RootTicketData", plist_new_data(data, len)); + plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len)); } else { info("NOTE: not sending RootTicketData (no data present)\n"); } @@ -1029,7 +1029,7 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl if (client->root_ticket) { dict = plist_new_dict(); - plist_dict_set_item(dict, "RootTicketData", plist_new_data(client->root_ticket, client->root_ticket_len)); + plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)client->root_ticket, client->root_ticket_len)); } else { unsigned char* data = NULL; unsigned int len = 0; @@ -1053,7 +1053,7 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl dict = plist_new_dict(); if (data && (len > 0)) { - plist_dict_set_item(dict, "RootTicketData", plist_new_data(data, len)); + plist_dict_set_item(dict, "RootTicketData", plist_new_data((char*)data, len)); } else { info("NOTE: not sending RootTicketData (no data present)\n"); } @@ -1118,7 +1118,7 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie } dict = plist_new_dict(); - blob = plist_new_data(data, size); + blob = plist_new_data((char*)data, size); char compkeyname[256]; sprintf(compkeyname, "%sFile", component_name); plist_dict_set_item(dict, compkeyname, blob); @@ -1279,7 +1279,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* } dict = plist_new_dict(); - plist_dict_set_item(dict, "LlbImageData", plist_new_data(llb_data, llb_size)); + plist_dict_set_item(dict, "LlbImageData", plist_new_data((char*)llb_data, llb_size)); free(llb_data); if (flash_version_1) { @@ -1339,13 +1339,13 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* component_size = 0; if (flash_version_1) { - plist_dict_set_item(norimage, component, plist_new_data(nor_data, nor_size)); + plist_dict_set_item(norimage, component, plist_new_data((char*)nor_data, nor_size)); } else { /* make sure iBoot is the first entry in the array */ if (!strncmp("iBoot", component, 5)) { - plist_array_insert_item(norimage, plist_new_data(nor_data, nor_size), 0); + plist_array_insert_item(norimage, plist_new_data((char*)nor_data, nor_size), 0); } else { - plist_array_append_item(norimage, plist_new_data(nor_data, nor_size)); + plist_array_append_item(norimage, plist_new_data((char*)nor_data, nor_size)); } } @@ -1381,7 +1381,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* return -1; } - plist_dict_set_item(dict, "RestoreSEPImageData", plist_new_data(personalized_data, personalized_size)); + plist_dict_set_item(dict, "RestoreSEPImageData", plist_new_data((char*)personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; @@ -1406,7 +1406,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* return -1; } - plist_dict_set_item(dict, "SEPImageData", plist_new_data(personalized_data, personalized_size)); + plist_dict_set_item(dict, "SEPImageData", plist_new_data((char*)personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; @@ -1431,7 +1431,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* return -1; } - plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data(personalized_data, personalized_size)); + plist_dict_set_item(dict, "SEPPatchImageData", plist_new_data((char*)personalized_data, personalized_size)); free(personalized_data); personalized_data = NULL; personalized_size = 0; @@ -1510,7 +1510,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } unsigned char* buffer = NULL; - unsigned char* blob = NULL; + const unsigned char* blob = NULL; unsigned char* fdata = NULL; uint64_t fsize = 0; uint64_t blob_size = 0; @@ -1607,9 +1607,8 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned free(buffer); buffer = NULL; - blob = NULL; blob_size = 0; - plist_get_data_val(node, &blob, &blob_size); + blob = (const unsigned char*)plist_get_data_ptr(node, &blob_size); if (!blob) { error("ERROR: could not get %s-Blob data\n", key); goto leave; @@ -1626,8 +1625,6 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned goto leave; } } - free(blob); - blob = NULL; fsize = (is_fls ? fls->size : mbn->size); fdata = (unsigned char*)malloc(fsize); @@ -1740,9 +1737,8 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned goto leave; } - blob = NULL; blob_size = 0; - plist_get_data_val(bbticket, &blob, &blob_size); + blob = (const unsigned char*)plist_get_data_ptr(bbticket, &blob_size); if (!blob) { error("ERROR: could not get BBTicket data\n"); goto leave; @@ -1752,8 +1748,6 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned error("ERROR: could not insert BBTicket to ebl.fls\n"); goto leave; } - free(blob); - blob = NULL; fsize = fls->size; fdata = (unsigned char*)malloc(fsize); @@ -1778,20 +1772,18 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned } } else { // add BBTicket as bbticket.der - blob = NULL; blob_size = 0; - plist_get_data_val(bbticket, &blob, &blob_size); + blob = (const unsigned char*)plist_get_data_ptr(bbticket, &blob_size); if (!blob) { error("ERROR: could not get BBTicket data\n"); goto leave; } - zs = zip_source_buffer(za, blob, blob_size, 1); + zs = zip_source_buffer(za, blob, blob_size, 0); if (!zs) { error("ERROR: out of memory\n"); goto leave; } - blob = NULL; if (zip_file_add(za, "bbticket.der", zs, ZIP_FL_OVERWRITE) == -1) { error("ERROR: could not add bbticket.der to archive\n"); @@ -1824,7 +1816,6 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned mbn_free(mbn); fls_free(fls); free(buffer); - free(blob); return res; } @@ -1839,7 +1830,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer uint64_t bb_nonce_size = 0; uint64_t bb_chip_id = 0; plist_t response = NULL; - uint8_t* buffer = NULL; + char* buffer = NULL; char* bbfwtmp = NULL; plist_t dict = NULL; @@ -1860,11 +1851,11 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer } plist_t bb_snum_node = plist_dict_get_item(arguments, "ChipSerialNo"); if (bb_snum_node && plist_get_node_type(bb_snum_node) == PLIST_DATA) { - plist_get_data_val(bb_snum_node, &bb_snum, &bb_snum_size); + plist_get_data_val(bb_snum_node, (char**)&bb_snum, &bb_snum_size); } plist_t bb_nonce_node = plist_dict_get_item(arguments, "Nonce"); if (bb_nonce_node && plist_get_node_type(bb_nonce_node) == PLIST_DATA) { - plist_get_data_val(bb_nonce_node, &bb_nonce, &bb_nonce_size); + plist_get_data_val(bb_nonce_node, (char**)&bb_nonce, &bb_nonce_size); } } @@ -1873,11 +1864,11 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer plist_t parameters = plist_new_dict(); plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); if (bb_nonce) { - plist_dict_set_item(parameters, "BbNonce", plist_new_data(bb_nonce, bb_nonce_size)); + plist_dict_set_item(parameters, "BbNonce", plist_new_data((const char*)bb_nonce, bb_nonce_size)); } plist_dict_set_item(parameters, "BbChipID", plist_new_uint(bb_chip_id)); plist_dict_set_item(parameters, "BbGoldCertId", plist_new_uint(bb_cert_id)); - plist_dict_set_item(parameters, "BbSNUM", plist_new_data(bb_snum, bb_snum_size)); + plist_dict_set_item(parameters, "BbSNUM", plist_new_data((const char*)bb_snum, bb_snum_size)); tss_parameters_add_from_manifest(parameters, build_identity, true); @@ -2109,7 +2100,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest error("ERROR: Unable to get personalized component: %s\n", component); } - plist_dict_set_item(data_dict, component, plist_new_data(data, size)); + plist_dict_set_item(data_dict, component, plist_new_data((const char*)data, size)); free(data); } } @@ -2256,7 +2247,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id error("ERROR: No 'SE ticket' in TSS response, this might not work\n"); } - plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2347,7 +2338,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc *(uint32_t*)(component_data + 4) = htole32((uint32_t)component_size); component_size += 16; - plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2429,7 +2420,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru comp_name = NULL; plist_t firmware_data = plist_new_dict(); - plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data(component_data, component_size)); + plist_dict_set_item(firmware_data, "YonkersFirmware", plist_new_data((char*)component_data, component_size)); plist_dict_set_item(response, "FirmwareData", firmware_data); free(component_data); @@ -2578,7 +2569,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct ftab_write(ftab, &component_data, &component_size); ftab_free(ftab); - plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2676,7 +2667,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str plist_to_bin(fw_map, &bin_plist, &bin_size); plist_free(fw_map); - plist_dict_set_item(response, "FirmwareData", plist_new_data((uint8_t*)bin_plist, bin_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data(bin_plist, bin_size)); free(bin_plist); return response; @@ -2798,7 +2789,7 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct return NULL; } - plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -2983,7 +2974,7 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct ftab_write(ftab, &component_data, &component_size); ftab_free(ftab); - plist_dict_set_item(response, "FirmwareData", plist_new_data(component_data, component_size)); + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; component_size = 0; @@ -3549,7 +3540,7 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi plist_t dict = plist_new_dict(); if (data != NULL) { // Send a chunk of file data - plist_dict_set_item(dict, "FileData", plist_new_data(data, size)); + plist_dict_set_item(dict, "FileData", plist_new_data((char*)data, size)); } else { // Send FileDataDone to mark end of transfer plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); @@ -3806,7 +3797,7 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer } plist_t dict = plist_new_dict(); - plist_dict_set_item(dict, "Ap,LocalPolicy", plist_new_data(data, size)); + plist_dict_set_item(dict, "Ap,LocalPolicy", plist_new_data((char*)data, size)); int restore_error = restored_send(restore, dict); if (restore_error != RESTORE_E_SUCCESS) { diff --git a/src/tss.c b/src/tss.c index 04d51087..99781ef7 100644 --- a/src/tss.c +++ b/src/tss.c @@ -961,9 +961,8 @@ int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t ove comp_name = (isprod) ? "Savage,B0-Prod-Patch" : "Savage,B0-Dev-Patch"; node = plist_dict_get_item(parameters, "Savage,Revision"); if (node && (plist_get_node_type(node) == PLIST_DATA)) { - unsigned char *savage_rev = NULL; uint64_t savage_rev_len = 0; - plist_get_data_val(node, &savage_rev, &savage_rev_len); + const unsigned char *savage_rev = (const unsigned char*)plist_get_data_ptr(node, &savage_rev_len); if (savage_rev_len > 0) { if (((savage_rev[0] | 0x10) & 0xF0) == 0x30) { comp_name = (isprod) ? "Savage,B2-Prod-Patch" : "Savage,B2-Dev-Patch"; @@ -971,7 +970,6 @@ int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t ove comp_name = (isprod) ? "Savage,BA-Prod-Patch" : "Savage,BA-Dev-Patch"; } } - free(savage_rev); } /* add Savage,B?-*-Patch */ @@ -1659,7 +1657,7 @@ static int tss_response_get_data_by_key(plist_t response, const char* name, unsi return -1; } - uint8_t* data = NULL; + char* data = NULL; uint64_t len = 0; plist_get_data_val(node, &data, &len); if (data) { @@ -1718,7 +1716,7 @@ int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char** uint32_t tss_size = 0; uint64_t blob_size = 0; char* entry_key = NULL; - uint8_t* blob_data = NULL; + char* blob_data = NULL; char* entry_path = NULL; plist_t tss_entry = NULL; plist_t blob_node = NULL; @@ -1772,7 +1770,7 @@ int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char** int tss_response_get_blob_by_entry(plist_t response, const char* entry, unsigned char** blob) { uint64_t blob_size = 0; - uint8_t* blob_data = NULL; + char* blob_data = NULL; plist_t blob_node = NULL; plist_t tss_entry = NULL; From c4c7d2339e9ceeeddb9f9465ff5cdd160a6a9358 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 18 May 2024 23:42:00 +0200 Subject: [PATCH 078/117] automake: Prevent `dist` or `distcheck` when uncommitted changes are present --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index c86bf426..efaae8e2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,4 +8,5 @@ EXTRA_DIST = \ git-version-gen dist-hook: + @if ! git diff --quiet; then echo "Uncommitted changes present; not releasing"; exit 1; fi echo $(VERSION) > $(distdir)/.tarball-version From 56d2c01505479b85e9aeddf58cd4237bf4242c2c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 18 May 2024 23:50:02 +0200 Subject: [PATCH 079/117] Add missing cast to silence compiler warning --- src/normal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/normal.c b/src/normal.c index 8070982b..e699bbe6 100644 --- a/src/normal.c +++ b/src/normal.c @@ -333,7 +333,7 @@ static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const } uint64_t n_size = 0; - plist_get_data_val(nonce_node, nonce, &n_size); + plist_get_data_val(nonce_node, (char**)nonce, &n_size); *nonce_size = (unsigned int)n_size; plist_free(nonce_node); From 04a3f49132522f514ef36117dd908990e278dbbc Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 23 May 2024 23:22:06 +0200 Subject: [PATCH 080/117] Link against the new libtatsu and remove tss code --- configure.ac | 3 + src/Makefile.am | 3 +- src/dfu.c | 3 +- src/idevicerestore.c | 3 +- src/img4.c | 3 +- src/recovery.c | 3 +- src/restore.c | 2 +- src/tss.c | 1794 ------------------------------------------ src/tss.h | 76 -- 9 files changed, 14 insertions(+), 1876 deletions(-) delete mode 100644 src/tss.c delete mode 100644 src/tss.h diff --git a/configure.ac b/configure.ac index 0b5fcea2..4686e199 100644 --- a/configure.ac +++ b/configure.ac @@ -20,6 +20,7 @@ LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.6.0 LIMD_GLUE_VERSION=1.2.0 +LIBTATSU_VERSION=1.0.0 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 OPENSSL_VERSION=0.9.8 @@ -29,6 +30,7 @@ AC_SUBST(LIBIMOBILEDEVICE_VERSION) AC_SUBST(LIBUSBMUXD_VERSION) AC_SUBST(LIBPLIST_VERSION) AC_SUBST(LIMD_GLUE_VERSION) +AC_SUBST(LIBTATSU_VERSION) AC_SUBST(LIBZIP_VERSION) AC_SUBST(LIBCURL_VERSION) AC_SUBST(OPENSSL_VERSION) @@ -44,6 +46,7 @@ PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= $LIBIMOBILEDEVICE_VE PKG_CHECK_MODULES(libusbmuxd, libusbmuxd-2.0 >= $LIBUSBMUXD_VERSION) PKG_CHECK_MODULES(libplist, libplist-2.0 >= $LIBPLIST_VERSION) PKG_CHECK_MODULES(limd_glue, libimobiledevice-glue-1.0 >= $LIMD_GLUE_VERSION) +PKG_CHECK_MODULES(libtatsu, libtatsu-1.0 >= $LIBTATSU_VERSION) PKG_CHECK_MODULES(libzip, libzip >= $LIBZIP_VERSION) PKG_CHECK_MODULES(libcurl, libcurl >= $LIBCURL_VERSION) PKG_CHECK_MODULES(zlib, zlib) diff --git a/src/Makefile.am b/src/Makefile.am index 722487a2..88602e50 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,7 @@ AM_CFLAGS = \ $(libusbmuxd_CFLAGS) \ $(libplist_CFLAGS) \ $(limd_glue_CFLAGS) \ + $(libtatsu_CFLAGS) \ $(libzip_CFLAGS) \ $(zlib_CFLAGS) \ $(openssl_CFLAGS) \ @@ -18,6 +19,7 @@ AM_LDFLAGS = \ $(libusbmuxd_LIBS) \ $(libplist_LIBS) \ $(limd_glue_LIBS) \ + $(libtatsu_LIBS) \ $(libzip_LIBS) \ $(zlib_LIBS) \ $(openssl_LIBS) \ @@ -31,7 +33,6 @@ idevicerestore_SOURCES = \ idevicerestore.c idevicerestore.h \ endianness.h \ common.c common.h \ - tss.c tss.h \ fls.c fls.h \ mbn.c mbn.h \ img3.c img3.h \ diff --git a/src/dfu.c b/src/dfu.c index cc8e1fbf..8557c292 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -27,8 +27,9 @@ #include #include +#include + #include "dfu.h" -#include "tss.h" #include "recovery.h" #include "idevicerestore.h" #include "common.h" diff --git a/src/idevicerestore.c b/src/idevicerestore.c index f27c3572..0b517b9f 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -46,10 +46,10 @@ #endif #include +#include #include "ace3.h" #include "dfu.h" -#include "tss.h" #include "img3.h" #include "img4.h" #include "ipsw.h" @@ -359,6 +359,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) idevice_set_debug_level(1); irecv_set_debug_level(1); } + tss_set_debug_level(client->debug_level); } idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.0); diff --git a/src/img4.c b/src/img4.c index 9a0cb29f..cfd3c934 100644 --- a/src/img4.c +++ b/src/img4.c @@ -22,9 +22,10 @@ #include #include +#include + #include "common.h" #include "img4.h" -#include "tss.h" #define ASN1_PRIVATE 0xc0 #define ASN1_PRIMITIVE_TAG 0x1f diff --git a/src/recovery.c b/src/recovery.c index e3fb4d19..afda4a97 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -29,8 +29,9 @@ #include #include +#include + #include "idevicerestore.h" -#include "tss.h" #include "img3.h" #include "restore.h" #include "recovery.h" diff --git a/src/restore.c b/src/restore.c index 050ee3b2..efb03f93 100644 --- a/src/restore.c +++ b/src/restore.c @@ -38,6 +38,7 @@ #endif #include #include +#include #include "idevicerestore.h" #include "asr.h" @@ -45,7 +46,6 @@ #include "fls.h" #include "mbn.h" #include "ftab.h" -#include "tss.h" #include "ipsw.h" #include "restore.h" #include "common.h" diff --git a/src/tss.c b/src/tss.c deleted file mode 100644 index 99781ef7..00000000 --- a/src/tss.c +++ /dev/null @@ -1,1794 +0,0 @@ -/* - * tss.c - * Functions for communicating with Apple's TSS server - * - * Copyright (c) 2010-2013 Martin Szulecki. All Rights Reserved. - * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. - * Copyright (c) 2010 Joshua Hill. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include - -#include "tss.h" -#include "img3.h" -#include "common.h" -#include "idevicerestore.h" - -#include "endianness.h" - -#define AUTH_VERSION "973.40.2" - -#ifdef WIN32 -#define TSS_CLIENT_VERSION_STRING "libauthinstall_Win-"AUTH_VERSION"" -#else -#define TSS_CLIENT_VERSION_STRING "libauthinstall-"AUTH_VERSION"" -#endif -#define ECID_STRSIZE 0x20 - -typedef struct { - int length; - char* content; -} tss_response; - -char* ecid_to_string(uint64_t ecid) -{ - char* ecid_string = malloc(ECID_STRSIZE); - memset(ecid_string, '\0', ECID_STRSIZE); - if (ecid == 0) { - error("ERROR: Invalid ECID passed.\n"); - return NULL; - } - snprintf(ecid_string, ECID_STRSIZE, "%"PRIu64, ecid); - return ecid_string; -} - -plist_t tss_request_new(plist_t overrides) -{ - plist_t request = plist_new_dict(); - - plist_dict_set_item(request, "@HostPlatformInfo", -#ifdef WIN32 - plist_new_string("windows") -#else - plist_new_string("mac") -#endif - ); - - plist_dict_set_item(request, "@VersionInfo", plist_new_string(TSS_CLIENT_VERSION_STRING)); - char* guid = generate_guid(); - if (guid) { - plist_dict_set_item(request, "@UUID", plist_new_string(guid)); - free(guid); - } - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return request; -} - -int tss_request_add_local_policy_tags(plist_t request, plist_t parameters) -{ - plist_dict_set_item(request, "@ApImg4Ticket", plist_new_bool(1)); - - if (plist_dict_copy_bool(request, parameters, "Ap,LocalBoot", NULL) < 0) { - error("ERROR: Unable to find required Ap,LocalBoot in parameters\n"); - return -1; - } - - if (plist_dict_copy_item(request, parameters, "Ap,LocalPolicy", NULL) < 0) { - error("ERROR: Unable to find required Ap,LocalPolicy in parameters\n"); - return -1; - } - - if (plist_dict_copy_data(request, parameters, "Ap,NextStageIM4MHash", NULL) < 0) { - error("ERROR: Unable to find required Ap,NextStageIM4MHash in parameters\n"); - return -1; - } - - plist_dict_copy_data(request, parameters, "Ap,RecoveryOSPolicyNonceHash", NULL); - plist_dict_copy_data(request, parameters, "Ap,VolumeUUID", NULL); - plist_dict_copy_uint(request, parameters, "ApECID", NULL); - plist_dict_copy_uint(request, parameters, "ApChipID", NULL); - plist_dict_copy_uint(request, parameters, "ApBoardID", NULL); - plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL); - plist_dict_copy_data(request, parameters, "ApNonce", NULL); - - if (!plist_dict_get_item(request, "ApSecurityMode")) { - /* copy from parameters if available */ - if (plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) { - error("ERROR: Unable to find required ApSecurityMode in parameters\n"); - return -1; - } - } - if (!plist_dict_get_item(request, "ApProductionMode")) { - /* copy from parameters if available */ - if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { - error("ERROR: Unable to find required ApProductionMode in parameters\n"); - return -1; - } - } - - return 0; -} - -int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, bool include_manifest) -{ - plist_t node = NULL; - - if (plist_dict_copy_data(parameters, build_identity, "UniqueBuildID", NULL) < 0) { - error("ERROR: Unable to find UniqueBuildID node\n"); - return -1; - } - - plist_dict_copy_string(parameters, build_identity, "Ap,OSLongVersion", NULL); - - if (plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL) < 0) {; - error("ERROR: Unable to find ApChipID node\n"); - return -1; - } - - if (plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL) < 0) { - error("ERROR: Unable to find ApBoardID node\n"); - return -1; - } - - plist_dict_copy_uint(parameters, build_identity, "ApSecurityDomain", NULL); - plist_dict_copy_uint(parameters, build_identity, "BMU,BoardID", NULL); - plist_dict_copy_uint(parameters, build_identity, "BMU,ChipID", NULL); - - if (plist_dict_copy_uint(parameters, build_identity, "BbChipID", NULL) < 0) { - debug("NOTE: Unable to find BbChipID node\n"); - } - - if (plist_dict_copy_data(parameters, build_identity, "BbProvisioningManifestKeyHash", NULL) < 0) { - debug("NOTE: Unable to find BbProvisioningManifestKeyHash node\n"); - } - - if (plist_dict_copy_data(parameters, build_identity, "BbActivationManifestKeyHash", NULL) < 0) { - debug("NOTE: Unable to find BbActivationManifestKeyHash node\n"); - } - - if (plist_dict_copy_data(parameters, build_identity, "BbCalibrationManifestKeyHash", NULL) < 0) { - debug("NOTE: Unable to find BbCalibrationManifestKeyHash node\n"); - } - - if (plist_dict_copy_data(parameters, build_identity, "BbFactoryActivationManifestKeyHash", NULL) < 0) { - debug("NOTE: Unable to find BbFactoryActivationManifestKeyHash node\n"); - } - - if (plist_dict_copy_data(parameters, build_identity, "BbFDRSecurityKeyHash", NULL) < 0) { - debug("NOTE: Unable to find BbFDRSecurityKeyHash node\n"); - } - - /* BbSkeyId - Used by XMM 6180/GSM */ - if (plist_dict_copy_data(parameters, build_identity, "BbSkeyId", NULL) < 0) { - debug("NOTE: Unable to find BbSkeyId node\n"); - } - - /* SE,ChipID - Used for SE firmware request */ - plist_dict_copy_uint(parameters, build_identity, "SE,ChipID", NULL); - - /* Savage,ChipID - Used for Savage firmware request */ - plist_dict_copy_uint(parameters, build_identity, "Savage,ChipID", NULL); - - /* add Savage,PatchEpoch - Used for Savage firmware request */ - plist_dict_copy_uint(parameters, build_identity, "Savage,PatchEpoch", NULL); - - /* Yonkers,BoardID - Used for Yonkers firmware request */ - plist_dict_copy_uint(parameters, build_identity, "Yonkers,BoardID", NULL); - - /* Yonkers,ChipID - Used for Yonkers firmware request */ - plist_dict_copy_uint(parameters, build_identity, "Yonkers,ChipID", NULL); - - /* add Yonkers,PatchEpoch - Used for Yonkers firmware request */ - plist_dict_copy_uint(parameters, build_identity, "Yonkers,PatchEpoch", NULL); - - plist_dict_copy_uint(parameters, build_identity, "Rap,BoardID", NULL); - plist_dict_copy_uint(parameters, build_identity, "Rap,ChipID", NULL); - plist_dict_copy_uint(parameters, build_identity, "Rap,SecurityDomain", NULL); - - plist_dict_copy_uint(parameters, build_identity, "Baobab,BoardID", NULL); - plist_dict_copy_uint(parameters, build_identity, "Baobab,ChipID", NULL); - plist_dict_copy_uint(parameters, build_identity, "Baobab,ManifestEpoch", NULL); - plist_dict_copy_uint(parameters, build_identity, "Baobab,SecurityDomain", NULL); - - plist_dict_copy_uint(parameters, build_identity, "eUICC,ChipID", NULL); - - plist_dict_copy_uint(parameters, build_identity, "NeRDEpoch", NULL); - plist_dict_copy_data(parameters, build_identity, "PearlCertificationRootPub", NULL); - - plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,1", NULL); - plist_dict_copy_uint(parameters, build_identity, "Timer,BoardID,2", NULL); - plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,1", NULL); - plist_dict_copy_uint(parameters, build_identity, "Timer,ChipID,2", NULL); - plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,1", NULL); - plist_dict_copy_uint(parameters, build_identity, "Timer,SecurityDomain,2", NULL); - - plist_dict_copy_item(parameters, build_identity, "Cryptex1,ChipID", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,Type", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,SubType", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,ProductClass", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,UseProductClass", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,NonceDomain", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,Version", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,PreauthorizationVersion", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,FakeRoot", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemOS", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemVolume", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,SystemTrustCache", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppOS", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppVolume", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,AppTrustCache", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainOS", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainVolume", NULL); - plist_dict_copy_item(parameters, build_identity, "Cryptex1,MobileAssetBrainTrustCache", NULL); - - plist_dict_copy_item(parameters, build_identity, "USBPortController1,BoardID", NULL); - plist_dict_copy_item(parameters, build_identity, "USBPortController1,ChipID", NULL); - plist_dict_copy_item(parameters, build_identity, "USBPortController1,SecurityDomain", NULL); - - node = plist_dict_get_item(build_identity, "Info"); - if (node) { - plist_dict_copy_bool(parameters, node, "RequiresUIDMode", NULL); - } - - if (include_manifest) { - /* add build identity manifest dictionary */ - node = plist_dict_get_item(build_identity, "Manifest"); - if (!node || plist_get_node_type(node) != PLIST_DICT) { - error("ERROR: Unable to find Manifest node\n"); - return -1; - } - plist_dict_set_item(parameters, "Manifest", plist_copy(node)); - } - - return 0; -} - -int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) -{ - if (!parameters) { - error("ERROR: Missing required AP parameters\n"); - return -1; - } - - plist_dict_copy_string(request, parameters, "Ap,OSLongVersion", NULL); - - if (plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { - error("ERROR: Unable to find required ApNonce in parameters\n"); - return -1; - } - - plist_dict_set_item(request, "@ApImg4Ticket", plist_new_bool(1)); - - if (!plist_dict_get_item(request, "ApSecurityMode")) { - /* copy from parameters if available */ - if (plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) { - error("ERROR: Unable to find required ApSecurityMode in parameters\n"); - return -1; - } - } - if (!plist_dict_get_item(request, "ApProductionMode")) { - /* ApProductionMode */ - if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { - error("ERROR: Unable to find required ApProductionMode in parameters\n"); - return -1; - } - } - - plist_dict_copy_data(request, parameters, "SepNonce", "ApSepNonce"); - plist_dict_copy_uint(request, parameters, "NeRDEpoch", NULL); - plist_dict_copy_data(request, parameters, "PearlCertificationRootPub", NULL); - - if (plist_dict_get_item(parameters, "UID_MODE")) { - plist_dict_copy_item(request, parameters, "UID_MODE", NULL); - } else if (plist_dict_get_bool(parameters, "RequiresUIDMode")) { - // The logic here is missing why this value is expected to be 'false' - plist_dict_set_item(request, "UID_MODE", plist_new_bool(0)); - } - - // FIXME: I didn't understand yet when this value is set, so for now we use a workaround - if (plist_dict_get_item(parameters, "ApSikaFuse")) { - plist_dict_copy_item(request, parameters, "Ap,SikaFuse", "ApSikaFuse"); - } else if (plist_dict_get_bool(parameters, "RequiresUIDMode")) { - // Workaround: We have only seen Ap,SikaFuse together with UID_MODE - plist_dict_set_item(request, "Ap,SikaFuse", plist_new_int(0)); - } - - return 0; -} - -int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters) -{ - if (!parameters) { - error("ERROR: Missing required AP parameters\n"); - return -1; - } - - if (plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) { - error("WARNING: Unable to find ApNonce in parameters\n"); - } - - plist_dict_set_item(request, "@APTicket", plist_new_bool(1)); - - if (plist_dict_copy_uint(request, parameters, "ApBoardID", NULL) < 0) { - error("ERROR: Unable to find required ApBoardID in request\n"); - return -1; - } - - if (plist_dict_copy_uint(request, parameters, "ApChipID", NULL) < 0) { - error("ERROR: Unable to find required ApChipID in request\n"); - return -1; - } - - if (plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL) < 0) { - error("ERROR: Unable to find required ApSecurityDomain in request\n"); - return -1; - } - - if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) { - error("ERROR: Unable to find required ApProductionMode in parameters\n"); - return -1; - } - - return 0; -} - -int tss_request_add_common_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - plist_dict_copy_uint(request, parameters, "ApECID", NULL); - plist_dict_copy_data(request, parameters, "UniqueBuildID", NULL); - plist_dict_copy_uint(request, parameters, "ApChipID", NULL); - plist_dict_copy_uint(request, parameters, "ApBoardID", NULL); - plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -static void tss_entry_apply_restore_request_rules(plist_t tss_entry, plist_t parameters, plist_t rules) -{ - if (!tss_entry || !rules) { - return; - } - if (plist_get_node_type(tss_entry) != PLIST_DICT) { - return; - } - if (plist_get_node_type(rules) != PLIST_ARRAY) { - return; - } - - uint32_t i; - for (i = 0; i < plist_array_get_size(rules); i++) { - plist_t rule = plist_array_get_item(rules, i); - plist_t conditions = plist_dict_get_item(rule, "Conditions"); - plist_dict_iter iter = NULL; - plist_dict_new_iter(conditions, &iter); - char* key = NULL; - plist_t value = NULL; - plist_t value2 = NULL; - int conditions_fulfilled = 1; - while (conditions_fulfilled) { - plist_dict_next_item(conditions, iter, &key, &value); - if (key == NULL) - break; - if (!strcmp(key, "ApRawProductionMode")) { - value2 = plist_dict_get_item(parameters, "ApProductionMode"); - } else if (!strcmp(key, "ApCurrentProductionMode")) { - value2 = plist_dict_get_item(parameters, "ApProductionMode"); - } else if (!strcmp(key, "ApRawSecurityMode")) { - value2 = plist_dict_get_item(parameters, "ApSecurityMode"); - } else if (!strcmp(key, "ApRequiresImage4")) { - value2 = plist_dict_get_item(parameters, "ApSupportsImg4"); - } else if (!strcmp(key, "ApDemotionPolicyOverride")) { - value2 = plist_dict_get_item(parameters, "DemotionPolicy"); - } else if (!strcmp(key, "ApInRomDFU")) { - value2 = plist_dict_get_item(parameters, "ApInRomDFU"); - } else { - error("WARNING: Unhandled condition '%s' while parsing RestoreRequestRules\n", key); - value2 = NULL; - } - if (value2) { - conditions_fulfilled = plist_compare_node_value(value, value2); - } else { - conditions_fulfilled = 0; - } - free(key); - } - free(iter); - iter = NULL; - - if (!conditions_fulfilled) { - continue; - } - - plist_t actions = plist_dict_get_item(rule, "Actions"); - plist_dict_new_iter(actions, &iter); - while (1) { - plist_dict_next_item(actions, iter, &key, &value); - if (key == NULL) - break; - uint8_t bv = 255; - plist_get_bool_val(value, &bv); - if (bv != 255) { - value2 = plist_dict_get_item(tss_entry, key); - if (value2) { - plist_dict_remove_item(tss_entry, key); - } - debug("DEBUG: Adding %s=%s to TSS entry\n", key, (bv) ? "true" : "false"); - plist_dict_set_item(tss_entry, key, plist_new_bool(bv)); - } - free(key); - } - } -} - -int tss_request_add_ap_recovery_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - /* loop over components from build manifest */ - plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: Unable to find restore manifest\n"); - return -1; - } - - /* add components to request */ - char* key = NULL; - plist_t manifest_entry = NULL; - plist_dict_iter iter = NULL; - plist_dict_new_iter(manifest_node, &iter); - while (1) { - free(key); - key = NULL; - plist_dict_next_item(manifest_node, iter, &key, &manifest_entry); - if (key == NULL) - break; - if (!manifest_entry || plist_get_node_type(manifest_entry) != PLIST_DICT) { - error("ERROR: Unable to fetch BuildManifest entry\n"); - free(key); - return -1; - } - - /* do not populate BaseBandFirmware, only in basebaseband request */ - if ((strcmp(key, "BasebandFirmware") == 0)) { - continue; - } - - // Compared to ac2, not needed for RecoveryOSRootTicket - if ((strcmp(key, "SE,UpdatePayload") == 0)) { - continue; - } - if ((strcmp(key, "BaseSystem") == 0)) { - continue; - } - if ((strcmp(key, "ANS") == 0)) { - continue; - } - if ((strcmp(key, "Ap,AudioBootChime") == 0)) { - continue; - } - if ((strcmp(key, "Ap,CIO") == 0)) { - continue; - } - if ((strcmp(key, "Ap,RestoreCIO") == 0)) { - continue; - } - if ((strcmp(key, "Ap,RestoreTMU") == 0)) { - continue; - } - if ((strcmp(key, "Ap,TMU") == 0)) { - continue; - } - if ((strcmp(key, "Ap,rOSLogo1") == 0)) { - continue; - } - if ((strcmp(key, "Ap,rOSLogo2") == 0)) { - continue; - } - if ((strcmp(key, "AppleLogo") == 0)) { - continue; - } - if ((strcmp(key, "DCP") == 0)) { - continue; - } - if ((strcmp(key, "LLB") == 0)) { - continue; - } - if ((strcmp(key, "RecoveryMode") == 0)) { - continue; - } - if ((strcmp(key, "RestoreANS") == 0)) { - continue; - } - if ((strcmp(key, "RestoreDCP") == 0)) { - continue; - } - if ((strcmp(key, "RestoreDeviceTree") == 0)) { - continue; - } - if ((strcmp(key, "RestoreKernelCache") == 0)) { - continue; - } - if ((strcmp(key, "RestoreLogo") == 0)) { - continue; - } - if ((strcmp(key, "RestoreRamDisk") == 0)) { - continue; - } - if ((strcmp(key, "RestoreSEP") == 0)) { - continue; - } - if ((strcmp(key, "SEP") == 0)) { - continue; - } - if ((strcmp(key, "ftap") == 0)) { - continue; - } - if ((strcmp(key, "ftsp") == 0)) { - continue; - } - if ((strcmp(key, "iBEC") == 0)) { - continue; - } - if ((strcmp(key, "iBSS") == 0)) { - continue; - } - if ((strcmp(key, "rfta") == 0)) { - continue; - } - if ((strcmp(key, "rfts") == 0)) { - continue; - } - - /* FIXME: only used with diagnostics firmware */ - if (strcmp(key, "Diags") == 0) { - continue; - } - - plist_t info_dict = plist_dict_get_item(manifest_entry, "Info"); - if (!info_dict) { - continue; - } - - if (plist_dict_get_bool(parameters, "_OnlyFWComponents")) { - if (!plist_dict_get_bool(manifest_entry, "Trusted")) { - debug("DEBUG: %s: Skipping '%s' as it is not trusted\n", __func__, key); - continue; - } - - if (!plist_dict_get_bool(info_dict, "IsFirmwarePayload") - && !plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") - && !plist_dict_get_bool(info_dict, "IsFUDFirmware") - && !plist_dict_get_bool(info_dict, "IsLoadedByiBoot") - && !plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") - && !plist_dict_get_bool(info_dict, "IsiBootEANFirmware") - && !plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware")) - { - debug("DEBUG: %s: Skipping '%s' as it is not a firmware payload\n", __func__, key); - continue; - } - } - - /* copy this entry */ - plist_t tss_entry = plist_copy(manifest_entry); - - /* remove obsolete Info node */ - plist_dict_remove_item(tss_entry, "Info"); - - /* 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", key); - tss_entry_apply_restore_request_rules(tss_entry, parameters, rules); - } - - /* Make sure we have a Digest key for Trusted items even if empty */ - if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { - debug("DEBUG: No Digest data, using empty value for entry %s\n", key); - plist_dict_set_item(tss_entry, "Digest", plist_new_data(NULL, 0)); - } - - /* finally add entry to request */ - plist_dict_set_item(request, key, tss_entry); - } - free(key); - free(iter); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - /* loop over components from build manifest */ - plist_t manifest_node = plist_dict_get_item(parameters, "Manifest"); - if (!manifest_node || plist_get_node_type(manifest_node) != PLIST_DICT) { - error("ERROR: Unable to find restore manifest\n"); - return -1; - } - - /* add components to request */ - char* key = NULL; - plist_t manifest_entry = NULL; - plist_dict_iter iter = NULL; - plist_dict_new_iter(manifest_node, &iter); - while (1) { - free(key); - key = NULL; - plist_dict_next_item(manifest_node, iter, &key, &manifest_entry); - if (key == NULL) - break; - if (!manifest_entry || plist_get_node_type(manifest_entry) != PLIST_DICT) { - error("ERROR: Unable to fetch BuildManifest entry\n"); - free(key); - return -1; - } - - /* do not populate BaseBandFirmware, only in basebaseband request */ - if ((strcmp(key, "BasebandFirmware") == 0)) { - continue; - } - - // Compared to ac2, not needed - if ((strcmp(key, "SE,UpdatePayload") == 0)) { - continue; - } - - // Compared to ac2, not needed - if ((strcmp(key, "BaseSystem") == 0)) { - continue; - } - - /* FIXME: only used with diagnostics firmware */ - if (strcmp(key, "Diags") == 0) { - continue; - } - - plist_t info_dict = plist_dict_get_item(manifest_entry, "Info"); - if (!info_dict) { - continue; - } - - if (plist_dict_get_bool(parameters, "ApSupportsImg4")) { - if (!plist_dict_get_item(info_dict, "RestoreRequestRules")) { - debug("DEBUG: %s: Skipping '%s' as it doesn't have RestoreRequestRules\n", __func__, key); - continue; - } - } - - int is_fw_payload = plist_dict_get_bool(info_dict, "IsFirmwarePayload") - || plist_dict_get_bool(info_dict, "IsSecondaryFirmwarePayload") - || plist_dict_get_bool(info_dict, "IsFUDFirmware") - || plist_dict_get_bool(info_dict, "IsLoadedByiBoot") - || plist_dict_get_bool(info_dict, "IsEarlyAccessFirmware") - || plist_dict_get_bool(info_dict, "IsiBootEANFirmware") - || plist_dict_get_bool(info_dict, "IsiBootNonEssentialFirmware"); - - if (plist_dict_get_bool(parameters, "_OnlyFWOrTrustedComponents")) { - if (!plist_dict_get_bool(manifest_entry, "Trusted") && !is_fw_payload) { - debug("DEBUG: %s: Skipping '%s' as it is neither firmware payload nor trusted\n", __func__, key); - continue; - } - } else if (plist_dict_get_bool(parameters, "_OnlyFWComponents")) { - if (!plist_dict_get_bool(manifest_entry, "Trusted")) { - debug("DEBUG: %s: Skipping '%s' as it is not trusted\n", __func__, key); - continue; - } - if (!is_fw_payload) { - debug("DEBUG: %s: Skipping '%s' as it is not a firmware payload\n", __func__, key); - continue; - } - } - - /* skip components with IsFTAB:true */ - if (plist_dict_get_bool(info_dict, "IsFTAB")) { - debug("DEBUG: %s: Skipping FTAB component '%s'\n", __func__, key); - continue; - } - - /* copy this entry */ - plist_t tss_entry = plist_copy(manifest_entry); - - /* remove obsolete Info node */ - plist_dict_remove_item(tss_entry, "Info"); - - /* 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", key); - tss_entry_apply_restore_request_rules(tss_entry, parameters, rules); - } - - /* Make sure we have a Digest key for Trusted items even if empty */ - if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "Digest")) { - debug("DEBUG: No Digest data, using empty value for entry %s\n", key); - plist_dict_set_item(tss_entry, "Digest", plist_new_data(NULL, 0)); - } - - /* finally add entry to request */ - plist_dict_set_item(request, key, tss_entry); - } - free(key); - free(iter); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_baseband_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - plist_t node = NULL; - - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - - plist_dict_copy_uint(request, parameters, "BbChipID", NULL); - plist_dict_copy_data(request, parameters, "BbProvisioningManifestKeyHash", NULL); - /* BbActivationManifestKeyHash - Used by Qualcomm MDM6610 */ - plist_dict_copy_data(request, parameters, "BbActivationManifestKeyHash", NULL); - plist_dict_copy_data(request, parameters, "BbCalibrationManifestKeyHash", NULL); - plist_dict_copy_data(request, parameters, "BbFactoryActivationManifestKeyHash", NULL); - plist_dict_copy_data(request, parameters, "BbFDRSecurityKeyHash", NULL); - /* BbSkeyId - Used by XMM 6180/GSM */ - plist_dict_copy_data(request, parameters, "BbSkeyId", NULL); - plist_dict_copy_data(request, parameters, "BbNonce", NULL); - plist_dict_copy_uint(request, parameters, "BbGoldCertId", NULL); - - uint64_t bb_chip_id = plist_dict_get_uint(request, "BbChipID"); - int32_t bb_cert_id = (int32_t)plist_dict_get_uint(request, "BbGoldCertId"); - - if (plist_dict_copy_data(request, parameters, "BbSNUM", NULL) < 0) { - error("ERROR: Unable to find required BbSNUM in parameters\n"); - return -1; - } - - /* BasebandFirmware */ - node = plist_access_path(parameters, 2, "Manifest", "BasebandFirmware"); - if (!node || plist_get_node_type(node) != PLIST_DICT) { - error("ERROR: Unable to get BasebandFirmware node\n"); - return -1; - } - plist_t bbfwdict = plist_copy(node); - node = NULL; - if (plist_dict_get_item(bbfwdict, "Info")) { - plist_dict_remove_item(bbfwdict, "Info"); - } - - if (bb_chip_id == 0x68) { - /* depending on the BasebandCertId remove certain nodes */ - if (bb_cert_id == 0x26F3FACC || bb_cert_id == 0x5CF2EC4E || bb_cert_id == 0x8399785A) { - plist_dict_remove_item(bbfwdict, "PSI2-PartialDigest"); - plist_dict_remove_item(bbfwdict, "RestorePSI2-PartialDigest"); - } else { - plist_dict_remove_item(bbfwdict, "PSI-PartialDigest"); - plist_dict_remove_item(bbfwdict, "RestorePSI-PartialDigest"); - } - } - - plist_dict_set_item(request, "BasebandFirmware", bbfwdict); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_se_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - 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; - } - - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - - if (plist_dict_copy_uint(request, parameters, "SE,ChipID", NULL) < 0) { - error("ERROR: %s: Unable to find required SE,ChipID in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_data(request, parameters, "SE,ID", NULL) < 0) { - error("ERROR: %s: Unable to find required SE,ID in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_data(request, parameters, "SE,Nonce", NULL) < 0) { - error("ERROR: %s: Unable to find required SE,Nonce in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_data(request, parameters, "SE,RootKeyIdentifier", NULL) < 0) { - error("ERROR: %s: Unable to find required SE,RootKeyIdentifier in parameters\n", __func__); - return -1; - } - - /* 'IsDev' determines whether we have Production or Development */ - uint8_t is_dev = plist_dict_get_bool(parameters, "SE,IsDev"); - - /* add SE,* components from build manifest to request */ - char* key = NULL; - plist_t manifest_entry = NULL; - plist_dict_iter iter = NULL; - plist_dict_new_iter(manifest_node, &iter); - while (1) { - free(key); - key = NULL; - plist_dict_next_item(manifest_node, iter, &key, &manifest_entry); - if (key == NULL) - break; - if (!manifest_entry || plist_get_node_type(manifest_entry) != PLIST_DICT) { - error("ERROR: Unable to fetch BuildManifest entry\n"); - free(key); - return -1; - } - - if (strncmp(key, "SE,", 3)) { - continue; - } - - /* copy this entry */ - plist_t tss_entry = plist_copy(manifest_entry); - - /* remove Info node */ - plist_dict_remove_item(tss_entry, "Info"); - - /* remove Development or Production key/hash node */ - if (is_dev) { - if (plist_dict_get_item(tss_entry, "ProductionCMAC")) - plist_dict_remove_item(tss_entry, "ProductionCMAC"); - if (plist_dict_get_item(tss_entry, "ProductionUpdatePayloadHash")) - plist_dict_remove_item(tss_entry, "ProductionUpdatePayloadHash"); - } else { - if (plist_dict_get_item(tss_entry, "DevelopmentCMAC")) - plist_dict_remove_item(tss_entry, "DevelopmentCMAC"); - if (plist_dict_get_item(tss_entry, "DevelopmentUpdatePayloadHash")) - plist_dict_remove_item(tss_entry, "DevelopmentUpdatePayloadHash"); - } - - /* add entry to request */ - plist_dict_set_item(request, key, tss_entry); - } - free(key); - free(iter); - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - /* fallback in case no @SE2,Ticket or @SE,Ticket was provided */ - if (!plist_dict_get_item(request, "@SE2,Ticket") && !plist_dict_get_item(request, "@SE,Ticket")) { - plist_dict_set_item(request, "@SE,Ticket", plist_new_bool(1)); - } - - return 0; -} - -int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name) -{ - 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)); - - if (plist_dict_copy_data(request, parameters, "Savage,UID", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,UID in parameters\n", __func__); - return -1; - } - - /* 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); - - if (plist_dict_copy_uint(request, parameters, "Savage,PatchEpoch", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,PatchEpoch in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_uint(request, parameters, "Savage,ChipID", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,ChipID in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_bool(request, parameters, "Savage,AllowOfflineBoot", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,AllowOfflineBoot in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_bool(request, parameters, "Savage,ReadFWKey", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,ReadFWKey in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_bool(request, parameters, "Savage,ProductionMode", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,ProductionMode in parameters\n", __func__); - return -1; - } - - const char *comp_name = NULL; - uint8_t isprod = plist_dict_get_bool(request, "Savage,ProductionMode"); - - /* get the right component name */ - comp_name = (isprod) ? "Savage,B0-Prod-Patch" : "Savage,B0-Dev-Patch"; - node = plist_dict_get_item(parameters, "Savage,Revision"); - if (node && (plist_get_node_type(node) == PLIST_DATA)) { - uint64_t savage_rev_len = 0; - const unsigned char *savage_rev = (const unsigned char*)plist_get_data_ptr(node, &savage_rev_len); - if (savage_rev_len > 0) { - if (((savage_rev[0] | 0x10) & 0xF0) == 0x30) { - comp_name = (isprod) ? "Savage,B2-Prod-Patch" : "Savage,B2-Dev-Patch"; - } else if ((savage_rev[0] & 0xF0) == 0xA0) { - comp_name = (isprod) ? "Savage,BA-Prod-Patch" : "Savage,BA-Dev-Patch"; - } - } - } - - /* add Savage,B?-*-Patch */ - node = plist_dict_get_item(manifest_node, comp_name); - if (!node) { - error("ERROR: Unable to get %s entry from manifest\n", comp_name); - return -1; - } - dict = plist_copy(node); - plist_dict_remove_item(dict, "Info"); - plist_dict_set_item(request, comp_name, dict); - - if (component_name) { - *component_name = strdup(comp_name); - } - - if (plist_dict_copy_data(request, parameters, "Savage,Nonce", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,Nonce in parameters\n", __func__); - return -1; - } - - if (plist_dict_copy_bool(request, parameters, "Savage,ReadECKey", NULL) < 0) { - error("ERROR: %s: Unable to find required Savage,ReadECKey in parameters\n", __func__); - return -1; - } - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_yonkers_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name) -{ - 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, "@Yonkers,Ticket", plist_new_bool(1)); - - /* 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); - - { - static const char *keys[] = {"Yonkers,AllowOfflineBoot", "Yonkers,BoardID", "Yonkers,ChipID", "Yonkers,ECID", "Yonkers,Nonce", "Yonkers,PatchEpoch", "Yonkers,ProductionMode", "Yonkers,ReadECKey", "Yonkers,ReadFWKey", }; - int i; - for (i = 0; i < (int)(sizeof(keys) / sizeof(keys[0])); ++i) { - node = plist_dict_get_item(parameters, keys[i]); - if (!node) { - error("ERROR: %s: Unable to find required %s in parameters\n", __func__, keys[i]); - } - plist_dict_set_item(request, keys[i], plist_copy(node)); - node = NULL; - } - } - - char *comp_name = NULL; - plist_t comp_node = NULL; - uint8_t isprod = plist_dict_get_bool(parameters, "Yonkers,ProductionMode"); - uint64_t fabrevision = plist_dict_get_uint(parameters, "Yonkers,FabRevision"); - - 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, "Yonkers,", 8) == 0) { - int target_node = 1; - plist_t sub_node; - if ((sub_node = plist_dict_get_item(node, "EPRO")) != NULL && plist_get_node_type(sub_node) == PLIST_BOOLEAN) { - uint8_t b = 0; - plist_get_bool_val(sub_node, &b); - target_node &= ((isprod) ? b : !b); - } - if ((sub_node = plist_dict_get_item(node, "FabRevision")) != NULL && plist_get_node_type(sub_node) == PLIST_UINT) { - uint64_t v = 0; - plist_get_uint_val(sub_node, &v); - target_node &= (v == fabrevision); - } - if (target_node) { - comp_node = node; - break; - } - } - free(comp_name); - } - free(iter); - - if (comp_name == NULL) { - error("ERROR: No Yonkers node for %s/%lu\n", (isprod) ? "Production" : "Development", (unsigned long)fabrevision); - return -1; - } - - /* add Yonkers,SysTopPatch* */ - if (comp_node != NULL) { - plist_t comp_dict = plist_copy(comp_node); - plist_dict_remove_item(comp_dict, "Info"); - plist_dict_set_item(request, comp_name, comp_dict); - } - - if (component_name) { - *component_name = comp_name; - } else { - free(comp_name); - } - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_vinyl_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 eUICC,Ticket */ - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_set_item(request, "@eUICC,Ticket", plist_new_bool(1)); - - plist_dict_copy_bool(request, parameters, "eUICC,ApProductionMode", "ApProductionMode"); - plist_dict_copy_uint(request, parameters, "eUICC,ChipID", NULL); - plist_dict_copy_data(request, parameters, "eUICC,EID", NULL); - plist_dict_copy_data(request, parameters, "eUICC,RootKeyIdentifier", NULL); - - if (!plist_dict_get_item(request, "eUICC,Gold")) { - plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Gold"); - if (n) { - plist_t p = plist_new_dict(); - plist_dict_copy_data(p, n, "Digest", NULL); - plist_dict_set_item(request, "eUICC,Gold", p); - } - } - - if (!plist_dict_get_item(request, "eUICC,Main")) { - plist_t n = plist_access_path(parameters, 2, "Manifest", "eUICC,Main"); - if (n) { - plist_t p = plist_new_dict(); - plist_dict_copy_data(p, n, "Digest", NULL); - plist_dict_set_item(request, "eUICC,Main", p); - } - } - - /* set Nonce for eUICC,Gold component */ - node = plist_dict_get_item(parameters, "EUICCGoldNonce"); - if (node) { - plist_t n = plist_dict_get_item(request, "eUICC,Gold"); - if (n) { - plist_dict_set_item(n, "Nonce", plist_copy(node)); - } - } - - /* set Nonce for eUICC,Main component */ - node = plist_dict_get_item(parameters, "EUICCMainNonce"); - if (node) { - plist_t n = plist_dict_get_item(request, "eUICC,Main"); - if (n) { - plist_dict_set_item(n, "Nonce", plist_copy(node)); - } - } - - /* apply overrides */ - if (overrides) { - plist_dict_merge(&request, overrides); - } - - return 0; -} - -int tss_request_add_rose_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 Rap,Ticket */ - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_set_item(request, "@Rap,Ticket", plist_new_bool(1)); - - plist_dict_copy_uint(request, parameters, "Rap,BoardID", NULL); - plist_dict_copy_uint(request, parameters, "Rap,ChipID", NULL); - plist_dict_copy_uint(request, parameters, "Rap,ECID", NULL); - plist_dict_copy_data(request, parameters, "Rap,Nonce", NULL); - plist_dict_copy_bool(request, parameters, "Rap,ProductionMode", NULL); - plist_dict_copy_uint(request, parameters, "Rap,SecurityDomain", NULL); - plist_dict_copy_bool(request, parameters, "Rap,SecurityMode", NULL); - plist_dict_copy_data(request, parameters, "Rap,FdrRootCaDigest", NULL); - - 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, "Rap,", 4) == 0) { - 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 */ - if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "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; -} - -int tss_request_add_veridian_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 BMU,Ticket */ - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_set_item(request, "@BMU,Ticket", plist_new_bool(1)); - - plist_dict_copy_uint(request, parameters, "BMU,BoardID", NULL); - plist_dict_copy_uint(request, parameters, "BMU,ChipID", "ChipID"); - plist_dict_copy_data(request, parameters, "BMU,Nonce", "Nonce"); - plist_dict_copy_bool(request, parameters, "BMU,ProductionMode", "ProductionMode"); - plist_dict_copy_uint(request, parameters, "BMU,UniqueID", "UniqueID"); - - 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, "BMU,", 4) == 0) { - 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 */ - if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "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; -} - -int tss_request_add_tcon_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 Baobab,Ticket */ - plist_dict_set_item(request, "@BBTicket", plist_new_bool(1)); - plist_dict_set_item(request, "@Baobab,Ticket", plist_new_bool(1)); - - plist_dict_copy_uint(request, parameters, "Baobab,BoardID", NULL); - plist_dict_copy_uint(request, parameters, "Baobab,ChipID", NULL); - plist_dict_copy_data(request, parameters, "Baobab,ECID", NULL); - plist_dict_copy_uint(request, parameters, "Baobab,Life", NULL); - plist_dict_copy_uint(request, parameters, "Baobab,ManifestEpoch", NULL); - plist_dict_copy_bool(request, parameters, "Baobab,ProductionMode", NULL); - plist_dict_copy_uint(request, parameters, "Baobab,SecurityDomain", NULL); - plist_dict_copy_data(request, parameters, "Baobab,UpdateNonce", NULL); - - uint8_t isprod = plist_dict_get_bool(parameters, "Baobab,ProductionMode"); - - 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, "Baobab,", 7) == 0) { - plist_t manifest_entry = plist_copy(node); - - plist_dict_remove_item(manifest_entry, "Info"); - plist_dict_set_item(manifest_entry, "EPRO", plist_new_bool(isprod)); - - /* 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; -} - -int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - plist_t node = NULL; - uint32_t tag = 0; - - 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); - plist_dict_copy_uint(request, parameters, key, NULL); - - sprintf(key, "Timer,ChipID,%u", tag); - plist_dict_copy_uint(request, parameters, key, NULL); - - sprintf(key, "Timer,SecurityDomain,%u", tag); - plist_dict_copy_uint(request, parameters, key, NULL); - - sprintf(key, "Timer,SecurityMode,%u", tag); - plist_dict_copy_bool(request, parameters, key, NULL); - - sprintf(key, "Timer,ProductionMode,%u", tag); - plist_dict_copy_bool(request, parameters, key, NULL); - - sprintf(key, "Timer,ECID,%u", tag); - plist_dict_copy_uint(request, parameters, key, NULL); - - sprintf(key, "Timer,Nonce,%u", tag); - plist_dict_copy_data(request, parameters, key, NULL); - - 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 */ - if (plist_dict_get_bool(manifest_entry, "Trusted") && !plist_dict_get_item(manifest_entry, "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; -} - -int tss_request_add_cryptex_tags(plist_t request, plist_t parameters, plist_t overrides) -{ - tss_request_add_common_tags(request, parameters, NULL); - - if (plist_dict_get_item(parameters, "Ap,LocalPolicy")) { - /* Cryptex1LocalPolicy */ - tss_request_add_local_policy_tags(request, parameters); - plist_dict_copy_data(request, parameters, "Ap,NextStageCryptex1IM4MHash", NULL); - } else { - /* Cryptex1 */ - plist_dict_set_item(request, "@Cryptex1,Ticket", plist_new_bool(1)); - - plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL); - plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL); - - plist_dict_iter iter = NULL; - plist_dict_new_iter(parameters, &iter); - plist_t value = NULL; - while (1) { - char *key = NULL; - plist_dict_next_item(parameters, iter, &key, &value); - if (key == NULL) - break; - if (strncmp(key, "Cryptex1", 8) == 0) { - plist_dict_set_item(request, key, plist_copy(value)); - } - free(key); - } - } - - /* 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) { - response->content = realloc(response->content, response->length + total + 1); - memcpy(response->content + response->length, data, total); - response->content[response->length + total] = '\0'; - response->length += total; - } - - return total; -} - -plist_t tss_request_send(plist_t tss_request, const char* server_url_string) -{ - if (idevicerestore_debug) { - debug_plist(tss_request); - } - - char* request = NULL; - int status_code = -1; - int retry = 0; - int max_retries = 15; - unsigned int size = 0; - char curl_error_message[CURL_ERROR_SIZE]; - - const char* urls[6] = { - "https://gs.apple.com/TSS/controller?action=2", - "https://17.171.36.30/TSS/controller?action=2", - "https://17.151.36.30/TSS/controller?action=2", - "http://gs.apple.com/TSS/controller?action=2", - "http://17.171.36.30/TSS/controller?action=2", - "http://17.151.36.30/TSS/controller?action=2" - }; - - plist_to_xml(tss_request, &request, &size); - - tss_response* response = NULL; - memset(curl_error_message, '\0', CURL_ERROR_SIZE); - - while (retry++ < max_retries) { - response = NULL; - CURL* handle = curl_easy_init(); - if (handle == NULL) { - break; - } - struct curl_slist* header = NULL; - header = curl_slist_append(header, "Cache-Control: no-cache"); - header = curl_slist_append(header, "Content-type: text/xml; charset=\"utf-8\""); - header = curl_slist_append(header, "Expect:"); - - response = malloc(sizeof(tss_response)); - if (response == NULL) { - fprintf(stderr, "Unable to allocate sufficient memory\n"); - return NULL; - } - - response->length = 0; - response->content = malloc(1); - response->content[0] = '\0'; - - /* disable SSL verification to allow download from untrusted https locations */ - curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); - - curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_message); - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&tss_write_callback); - curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); - curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header); - curl_easy_setopt(handle, CURLOPT_POSTFIELDS, request); - curl_easy_setopt(handle, CURLOPT_USERAGENT, USER_AGENT_STRING); - curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, strlen(request)); - if (server_url_string) { - curl_easy_setopt(handle, CURLOPT_URL, server_url_string); - info("Request URL set to %s\n", server_url_string); - } else { - int url_index = (retry - 1) % 6; - curl_easy_setopt(handle, CURLOPT_URL, urls[url_index]); - info("Request URL set to %s\n", urls[url_index]); - } - - info("Sending TSS request attempt %d... ", retry); - - curl_easy_perform(handle); - curl_slist_free_all(header); - curl_easy_cleanup(handle); - - if (strstr(response->content, "MESSAGE=SUCCESS")) { - status_code = 0; - info("response successfully received\n"); - break; - } - - if (response->length > 0) { - error("TSS server returned: %s\n", response->content); - } - - char* status = strstr(response->content, "STATUS="); - if (status) { - sscanf(status+7, "%d&%*s", &status_code); - } - if (status_code == -1) { - error("%s\n", curl_error_message); - // no status code in response. retry - free(response->content); - free(response); - response = NULL; - sleep(2); - continue; - } else if (status_code == 8) { - // server error (invalid bb request?) - break; - } else if (status_code == 49) { - // server error (invalid bb data, e.g. BbSNUM?) - break; - } else if (status_code == 69 || status_code == 94) { - // This device isn't eligible for the requested build. - break; - } else if (status_code == 100) { - // server error, most likely the request was malformed - break; - } else if (status_code == 126) { - // An internal error occured, most likely the request was malformed - break; - } else { - error("ERROR: tss_send_request: Unhandled status code %d\n", status_code); - } - } - - if (status_code != 0) { - if (response && strstr(response->content, "MESSAGE=") != NULL) { - char* message = strstr(response->content, "MESSAGE=") + strlen("MESSAGE="); - error("ERROR: TSS request failed (status=%d, message=%s)\n", status_code, message); - } else { - error("ERROR: TSS request failed: %s (status=%d)\n", curl_error_message, status_code); - } - free(request); - if (response) free(response->content); - if (response) free(response); - return NULL; - } - - char* tss_data = strstr(response->content, "content); - free(response); - return NULL; - } - - uint32_t tss_size = 0; - plist_t tss_response = NULL; - tss_size = response->length - (tss_data - response->content); - plist_from_xml(tss_data, tss_size, &tss_response); - free(response->content); - free(response); - - if (idevicerestore_debug) { - debug_plist(tss_response); - } - - free(request); - - return tss_response; -} - -static int tss_response_get_data_by_key(plist_t response, const char* name, unsigned char** buffer, unsigned int* length) -{ - plist_t node = plist_dict_get_item(response, name); - if (!node || plist_get_node_type(node) != PLIST_DATA) { - debug("DEBUG: %s: No entry '%s' in TSS response\n", __func__, name); - return -1; - } - - char* data = NULL; - uint64_t len = 0; - plist_get_data_val(node, &data, &len); - if (data) { - *length = (unsigned int)len; - *buffer = (unsigned char*)data; - return 0; - } else { - error("ERROR: Unable to get %s data from TSS response\n", name); - return -1; - } -} - -int tss_response_get_ap_img4_ticket(plist_t response, unsigned char** ticket, unsigned int* length) -{ - return tss_response_get_data_by_key(response, "ApImg4Ticket", ticket, length); -} - -int tss_response_get_ap_ticket(plist_t response, unsigned char** ticket, unsigned int* length) -{ - return tss_response_get_data_by_key(response, "APTicket", ticket, length); -} - -int tss_response_get_baseband_ticket(plist_t response, unsigned char** ticket, unsigned int* length) -{ - return tss_response_get_data_by_key(response, "BBTicket", ticket, length); -} - -int tss_response_get_path_by_entry(plist_t response, const char* entry, char** path) -{ - char* path_string = NULL; - plist_t path_node = NULL; - plist_t entry_node = NULL; - - *path = NULL; - - entry_node = plist_dict_get_item(response, entry); - if (!entry_node || plist_get_node_type(entry_node) != PLIST_DICT) { - debug("DEBUG: %s: No entry '%s' in TSS response\n", __func__, entry); - return -1; - } - - path_node = plist_dict_get_item(entry_node, "Path"); - if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) { - debug("NOTE: Unable to find %s path in TSS entry\n", entry); - return -1; - } - plist_get_string_val(path_node, &path_string); - - *path = path_string; - return 0; -} - -int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char** blob) -{ - uint32_t i = 0; - uint32_t tss_size = 0; - uint64_t blob_size = 0; - char* entry_key = NULL; - char* blob_data = NULL; - char* entry_path = NULL; - plist_t tss_entry = NULL; - plist_t blob_node = NULL; - plist_t path_node = NULL; - plist_dict_iter iter = NULL; - - *blob = NULL; - - plist_dict_new_iter(tss, &iter); - tss_size = plist_dict_get_size(tss); - for (i = 0; i < tss_size; i++) { - plist_dict_next_item(tss, iter, &entry_key, &tss_entry); - if (entry_key == NULL) - break; - - if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) { - continue; - } - - path_node = plist_dict_get_item(tss_entry, "Path"); - if (!path_node || plist_get_node_type(path_node) != PLIST_STRING) { - error("ERROR: Unable to find TSS path node in entry %s\n", entry_key); - free(iter); - return -1; - } - - plist_get_string_val(path_node, &entry_path); - if (strcmp(path, entry_path) == 0) { - blob_node = plist_dict_get_item(tss_entry, "Blob"); - if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { - error("ERROR: Unable to find TSS blob node in entry %s\n", entry_key); - free(iter); - return -1; - } - plist_get_data_val(blob_node, &blob_data, &blob_size); - break; - } - - free(entry_key); - } - free(iter); - - if (blob_data == NULL || blob_size <= 0) { - return -1; - } - - *blob = (unsigned char*)blob_data; - return 0; -} - -int tss_response_get_blob_by_entry(plist_t response, const char* entry, unsigned char** blob) -{ - uint64_t blob_size = 0; - char* blob_data = NULL; - plist_t blob_node = NULL; - plist_t tss_entry = NULL; - - *blob = NULL; - - tss_entry = plist_dict_get_item(response, entry); - if (!tss_entry || plist_get_node_type(tss_entry) != PLIST_DICT) { - debug("DEBUG: %s: No entry '%s' in TSS response\n", __func__, entry); - return -1; - } - - blob_node = plist_dict_get_item(tss_entry, "Blob"); - if (!blob_node || plist_get_node_type(blob_node) != PLIST_DATA) { - error("ERROR: Unable to find blob in %s entry\n", entry); - return -1; - } - plist_get_data_val(blob_node, &blob_data, &blob_size); - - *blob = (unsigned char*)blob_data; - return 0; -} diff --git a/src/tss.h b/src/tss.h deleted file mode 100644 index 8af2fcca..00000000 --- a/src/tss.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * tss.h - * Definitions for communicating with Apple's TSS server. - * - * Copyright (c) 2013 Martin Szulecki. All Rights Reserved. - * Copyright (c) 2012 Nikias Bassen. All Rights Reserved. - * Copyright (c) 2010 Joshua Hill. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef IDEVICERESTORE_TSS_H -#define IDEVICERESTORE_TSS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/* parameters */ -int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, bool include_manifest); - -/* request */ -plist_t tss_request_new(plist_t overrides); - -int tss_request_add_local_policy_tags(plist_t request, plist_t parameters); -int tss_request_add_common_tags(plist_t request, plist_t parameters, plist_t overrides); -int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrides); -int tss_request_add_ap_recovery_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, char **component_name); -int tss_request_add_yonkers_tags(plist_t request, plist_t parameters, plist_t overrides, char **component_name); -int tss_request_add_vinyl_tags(plist_t request, plist_t parameters, plist_t overrides); -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_cryptex_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); - -/* i/o */ -plist_t tss_request_send(plist_t request, const char* server_url_string); - -/* response */ -int tss_response_get_ap_img4_ticket(plist_t response, unsigned char** ticket, unsigned int* length); -int tss_response_get_ap_ticket(plist_t response, unsigned char** ticket, unsigned int* length); -int tss_response_get_baseband_ticket(plist_t response, unsigned char** ticket, unsigned int* length); -int tss_response_get_path_by_entry(plist_t response, const char* entry, char** path); -int tss_response_get_blob_by_path(plist_t response, const char* path, unsigned char** blob); -int tss_response_get_blob_by_entry(plist_t response, const char* entry, unsigned char** blob); - -/* helpers */ -char* ecid_to_string(uint64_t ecid); - -#ifdef __cplusplus -} -#endif - -#endif From df06f4d859f7bb0896d1b15ade5b9d2b58626a0e Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 23 May 2024 23:38:26 +0200 Subject: [PATCH 081/117] [github-actions] Update build workflow to use new libtatsu --- .github/workflows/build.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 76d4a0b8..c07d02ae 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,6 +48,13 @@ jobs: workflow: build.yml name: libimobiledevice-latest_${{env.target_triplet}} repo: libimobiledevice/libimobiledevice + - name: fetch libtatsu + uses: dawidd6/action-download-artifact@v3 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: build.yml + name: libtatsu-latest_${{env.target_triplet}} + repo: libimobiledevice/libtatsu - name: install external dependencies run: | mkdir extract @@ -122,6 +129,13 @@ jobs: workflow: build.yml name: libimobiledevice-latest_macOS repo: libimobiledevice/libimobiledevice + - name: fetch libtatsu + uses: dawidd6/action-download-artifact@v3 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: build.yml + name: libtatsu-latest_macOS + repo: libimobiledevice/libtatsu - name: install external dependencies run: | mkdir extract @@ -253,6 +267,13 @@ jobs: workflow: build.yml name: libimobiledevice-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libimobiledevice + - name: fetch libtatsu + uses: dawidd6/action-download-artifact@v3 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: build.yml + name: libtatsu-latest_${{ matrix.arch }}-${{ env.dest }} + repo: libimobiledevice/libtatsu - name: install external dependencies run: | mkdir extract From 4ed598bdf865de7d2f202e6d6b9d1d39529f0e8d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 5 Jun 2024 18:24:16 +0200 Subject: [PATCH 082/117] Small change to align with updated libtatsu --- configure.ac | 2 +- src/idevicerestore.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 4686e199..545b235a 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.6.0 LIMD_GLUE_VERSION=1.2.0 -LIBTATSU_VERSION=1.0.0 +LIBTATSU_VERSION=1.0.1 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 OPENSSL_VERSION=0.9.8 diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 0b517b9f..538562de 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -2170,7 +2170,7 @@ int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_ return -1; } - plist_dict_set_item(parameters, "_OnlyFWOrTrustedComponents", plist_new_bool(1)); + plist_dict_set_item(parameters, "_OnlyFWComponents", plist_new_bool(1)); /* add tags from manifest */ if (tss_request_add_ap_tags(request, parameters, NULL) < 0) { From 9a4266a39da9bd741dda6aa1c15464ef67bba8d4 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 12 Jun 2024 15:09:23 +0200 Subject: [PATCH 083/117] Add missing linebreak to log message --- src/idevicerestore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 538562de..25442218 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1495,7 +1495,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) // device is finally in restore mode, let's do this if (client->mode == MODE_RESTORE) { if ((client->flags & FLAG_NO_RESTORE) != 0) { - info("Device is now in restore mode. Exiting as requested."); + info("Device is now in restore mode. Exiting as requested.\n"); return 0; } client->ignore_device_add_events = 1; From 4e95bd957981ba6bb1fc56d5f0f9781ed9fa8123 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 12 Jun 2024 19:27:38 +0200 Subject: [PATCH 084/117] Require libtatsu 1.0.2 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 545b235a..25d1e952 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.6.0 LIMD_GLUE_VERSION=1.2.0 -LIBTATSU_VERSION=1.0.1 +LIBTATSU_VERSION=1.0.2 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 OPENSSL_VERSION=0.9.8 From 10cd5f7f0fe14fbf51f2142ea2df153da33d1a21 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 16 Jun 2024 15:53:29 +0200 Subject: [PATCH 085/117] Remove OpenSSL dependency in favor of libimobiledevice-glue's hash functions This also removes the sha1/sha384 code from this repository since we are using the ones from libimobiledevice-glue now. --- .github/workflows/build.yml | 12 -- configure.ac | 33 +--- src/Makefile.am | 5 - src/asr.c | 19 +-- src/fixedint.h | 72 --------- src/idevicerestore.c | 14 +- src/ipsw.c | 18 +-- src/sha1.c | 294 --------------------------------- src/sha1.h | 44 ----- src/sha512.c | 314 ------------------------------------ src/sha512.h | 32 ---- 11 files changed, 13 insertions(+), 844 deletions(-) delete mode 100644 src/fixedint.h delete mode 100644 src/sha1.c delete mode 100644 src/sha1.h delete mode 100644 src/sha512.c delete mode 100644 src/sha512.h diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c07d02ae..bd2bdd58 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -158,18 +158,7 @@ jobs: export CFLAGS="$USEARCHS -isysroot $SDKDIR" echo "Using CFLAGS: $CFLAGS" echo "BUILD_CFLAGS=$CFLAGS" >> $GITHUB_ENV - mkdir -p lib - curl -o lib/libcrypto.35.tbd -Ls \ - https://gist.github.com/nikias/94c99fd145a75a5104415e5117b0cafa/raw/5209dfbff5a871a14272afe4794e76eb4cf6f062/libcrypto.35.tbd - curl -o lib/libssl.35.tbd -Ls \ - https://gist.github.com/nikias/94c99fd145a75a5104415e5117b0cafa/raw/5209dfbff5a871a14272afe4794e76eb4cf6f062/libssl.35.tbd - LIBRESSL_VER=2.2.7 - FILENAME="libressl-$LIBRESSL_VER.tar.gz" - curl -o $FILENAME -Ls "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/$FILENAME" mkdir -p deps - tar -C deps -xzf $FILENAME - echo "LIBRESSL_CFLAGS=-I`pwd`/deps/libressl-$LIBRESSL_VER/include" >> $GITHUB_ENV - echo "LIBRESSL_LIBS=-Xlinker `pwd`/lib/libssl.35.tbd -Xlinker `pwd`/lib/libcrypto.35.tbd" >> $GITHUB_ENV FILENAME="libzip-static.tar.bz2" curl -o $FILENAME.b64 -Ls "https://gist.github.com/nikias/3da15d03120382f87b44029cd8495a02/raw/99cd8138fed99e8f6530b6f179f787342c698e1f/libzip-1.7.1_static_macOS.tar.bz2" base64 -D < $FILENAME.b64 > $FILENAME @@ -181,7 +170,6 @@ jobs: export CFLAGS="${{env.BUILD_CFLAGS}} -Wno-nullability-completeness -Wno-expansion-to-defined" echo "Using CFLAGS: $CFLAGS" ./autogen.sh PKG_CONFIG_PATH=/usr/local/lib/pkgconfig \ - openssl_CFLAGS="$LIBRESSL_CFLAGS" openssl_LIBS="$LIBRESSL_LIBS" \ libcurl_CFLAGS="-I${{env.SDKDIR}}/usr/include" libcurl_LIBS="-lcurl" \ libzip_CFLAGS="$LIBZIP_CFLAGS" libzip_LIBS="$LIBZIP_LIBS" \ zlib_CFLAGS="-I${{env.SDKDIR}}/usr/include" zlib_LIBS="-lz" \ diff --git a/configure.ac b/configure.ac index 25d1e952..d2c7f32e 100644 --- a/configure.ac +++ b/configure.ac @@ -19,11 +19,10 @@ LIBIRECOVERY_VERSION=1.2.0 LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.6.0 -LIMD_GLUE_VERSION=1.2.0 +LIMD_GLUE_VERSION=1.3.0 LIBTATSU_VERSION=1.0.2 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 -OPENSSL_VERSION=0.9.8 AC_SUBST(LIBIRECOVERY_VERSION) AC_SUBST(LIBIMOBILEDEVICE_VERSION) @@ -33,7 +32,6 @@ AC_SUBST(LIMD_GLUE_VERSION) AC_SUBST(LIBTATSU_VERSION) AC_SUBST(LIBZIP_VERSION) AC_SUBST(LIBCURL_VERSION) -AC_SUBST(OPENSSL_VERSION) # Checks for programs. AC_PROG_CC @@ -51,9 +49,6 @@ PKG_CHECK_MODULES(libzip, libzip >= $LIBZIP_VERSION) PKG_CHECK_MODULES(libcurl, libcurl >= $LIBCURL_VERSION) PKG_CHECK_MODULES(zlib, zlib) -# optional -PKG_CHECK_MODULES(openssl, openssl >= $OPENSSL_VERSION, have_openssl=yes, have_openssl=no) - AC_CHECK_FUNCS([strsep strcspn mkstemp realpath]) if test x$ac_cv_func_strsep != xyes; then if test x$ac_cv_func_strcspn != xyes; then @@ -156,32 +151,6 @@ fi CFLAGS="$CACHED_CFLAGS" -AC_ARG_WITH([openssl], - [AS_HELP_STRING([--without-openssl], - [Do not use OpenSSL])], - [use_openssl=$withval], - [use_openssl=$have_openssl]) - -if test "x$use_openssl" == "xyes"; then - if test "x$have_openssl" != "xyes"; then - echo "*** NOTE: --with-openssl passed but OpenSSL is not available ***" - use_openssl=no - fi -fi -if test "x$use_openssl" != "xyes"; then - echo "*** NOTE: Using internal SHA1 implementation ***" - have_openssl=no - openssl_CFLAGS= - openssl_LIBS= -fi -if test "x$have_openssl" == "xyes"; then - AC_DEFINE(HAVE_OPENSSL, [1], [Define if you have OpenSSL]) -fi -AC_SUBST(openssl_CFLAGS) -AC_SUBST(openssl_LIBS) - -AM_CONDITIONAL(USE_INTERNAL_SHA, test x$use_openssl != xyes) - AC_SUBST(GLOBAL_CFLAGS) AC_SUBST(AC_LDFLAGS) AC_SUBST(AC_LDADD) diff --git a/src/Makefile.am b/src/Makefile.am index 88602e50..80f02f20 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,7 +9,6 @@ AM_CFLAGS = \ $(libtatsu_CFLAGS) \ $(libzip_CFLAGS) \ $(zlib_CFLAGS) \ - $(openssl_CFLAGS) \ $(libcurl_CFLAGS) AM_LDFLAGS = \ @@ -22,7 +21,6 @@ AM_LDFLAGS = \ $(libtatsu_LIBS) \ $(libzip_LIBS) \ $(zlib_LIBS) \ - $(openssl_LIBS) \ $(libcurl_LIBS) AM_LDADD = $(AC_LDADD) @@ -50,9 +48,6 @@ idevicerestore_SOURCES = \ limera1n.c limera1n.h \ download.c download.h \ locking.c locking.h -if USE_INTERNAL_SHA -idevicerestore_SOURCES += sha1.c sha1.h sha512.c sha512.h fixedint.h -endif idevicerestore_CFLAGS = $(AM_CFLAGS) idevicerestore_LDFLAGS = $(AM_LDFLAGS) idevicerestore_LDADD = $(AM_LDADD) diff --git a/src/asr.c b/src/asr.c index bf15dc21..aadf25a1 100644 --- a/src/asr.c +++ b/src/asr.c @@ -30,15 +30,8 @@ #include #include #include -#ifdef HAVE_OPENSSL -#include -#else -#include "sha1.h" -#define SHA_CTX SHA1_CTX -#define SHA1_Init SHA1Init -#define SHA1_Update SHA1Update -#define SHA1_Final SHA1Final -#endif + +#include #include "asr.h" #include "idevicerestore.h" @@ -343,12 +336,6 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) data = (char*)malloc(ASR_PAYLOAD_CHUNK_SIZE + 20); - SHA_CTX sha1; - - if (asr->checksum_chunks) { - SHA1_Init(&sha1); - } - i = length; int retry = 3; while(i > 0 && retry >= 0) { @@ -367,7 +354,7 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) sendsize = size; if (asr->checksum_chunks) { - SHA1((unsigned char*)data, size, (unsigned char*)(data+size)); + sha1((unsigned char*)data, size, (unsigned char*)(data+size)); sendsize += 20; } if (asr_send_buffer(asr, data, sendsize) < 0) { diff --git a/src/fixedint.h b/src/fixedint.h deleted file mode 100644 index 1a8745b1..00000000 --- a/src/fixedint.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - Portable header to provide the 32 and 64 bits type. - - Not a compatible replacement for , do not blindly use it as such. -*/ - -#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED) - #include - #define FIXEDINT_H_INCLUDED - - #if defined(__WATCOMC__) && __WATCOMC__ >= 1250 && !defined(UINT64_C) - #include - #define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX)) - #endif -#endif - - -#ifndef FIXEDINT_H_INCLUDED - #define FIXEDINT_H_INCLUDED - - #include - - /* (u)int32_t */ - #ifndef uint32_t - #if (ULONG_MAX == 0xffffffffUL) - typedef unsigned long uint32_t; - #elif (UINT_MAX == 0xffffffffUL) - typedef unsigned int uint32_t; - #elif (USHRT_MAX == 0xffffffffUL) - typedef unsigned short uint32_t; - #endif - #endif - - - #ifndef int32_t - #if (LONG_MAX == 0x7fffffffL) - typedef signed long int32_t; - #elif (INT_MAX == 0x7fffffffL) - typedef signed int int32_t; - #elif (SHRT_MAX == 0x7fffffffL) - typedef signed short int32_t; - #endif - #endif - - - /* (u)int64_t */ - #if (defined(__STDC__) && defined(__STDC_VERSION__) && __STDC__ && __STDC_VERSION__ >= 199901L) - typedef long long int64_t; - typedef unsigned long long uint64_t; - - #define UINT64_C(v) v ##ULL - #define INT64_C(v) v ##LL - #elif defined(__GNUC__) - __extension__ typedef long long int64_t; - __extension__ typedef unsigned long long uint64_t; - - #define UINT64_C(v) v ##ULL - #define INT64_C(v) v ##LL - #elif defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__APPLE_CC__) || defined(_LONG_LONG) || defined(_CRAYC) - typedef long long int64_t; - typedef unsigned long long uint64_t; - - #define UINT64_C(v) v ##ULL - #define INT64_C(v) v ##LL - #elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || defined(__alpha) || defined(__DECC) - typedef __int64 int64_t; - typedef unsigned __int64 uint64_t; - - #define UINT64_C(v) v ##UI64 - #define INT64_C(v) v ##I64 - #endif -#endif diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 25442218..309f2b69 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -38,13 +38,7 @@ #include -#ifdef HAVE_OPENSSL -#include -#else -#include "sha512.h" -#define SHA384 sha384 -#endif - +#include #include #include @@ -2495,7 +2489,7 @@ int get_recovery_os_local_policy_tss_response( // Add Ap,LocalPolicy uint8_t digest[SHA384_DIGEST_LENGTH]; - SHA384(lpol_file, lpol_file_length, digest); + sha384(lpol_file, lpol_file_length, digest); plist_t lpol = plist_new_dict(); plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); @@ -2590,7 +2584,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ // Add Ap,LocalPolicy uint8_t digest[SHA384_DIGEST_LENGTH]; - SHA384(lpol_file, lpol_file_length, digest); + sha384(lpol_file, lpol_file_length, digest); plist_t lpol = plist_new_dict(); plist_dict_set_item(lpol, "Digest", plist_new_data((char*)digest, SHA384_DIGEST_LENGTH)); plist_dict_set_item(lpol, "Trusted", plist_new_bool(1)); @@ -2603,7 +2597,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_ tss_response_get_ap_img4_ticket(client->tss, &ticket, &ticket_length); // Hash it and add it as Ap,NextStageIM4MHash uint8_t hash[SHA384_DIGEST_LENGTH]; - SHA384(ticket, ticket_length, hash); + sha384(ticket, ticket_length, hash); plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_new_data((char*)hash, SHA384_DIGEST_LENGTH)); /* create basic request */ diff --git a/src/ipsw.c b/src/ipsw.c index c25f61d3..6a747f40 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -34,16 +34,8 @@ #include #include #include -#ifdef HAVE_OPENSSL -#include -#else -#include "sha1.h" -#define SHA_CTX SHA1_CTX -#define SHA1_Init SHA1Init -#define SHA1_Update SHA1Update -#define SHA1_Final SHA1Final -#endif +#include #include #include @@ -1176,14 +1168,14 @@ static int sha1_verify_fp(FILE* f, unsigned char* expected_sha1) unsigned char tsha1[20]; char buf[8192]; if (!f) return 0; - SHA_CTX sha1ctx; - SHA1_Init(&sha1ctx); + sha1_context sha1ctx; + sha1_init(&sha1ctx); rewind(f); while (!feof(f)) { size_t sz = fread(buf, 1, 8192, f); - SHA1_Update(&sha1ctx, (const void*)buf, sz); + sha1_update(&sha1ctx, buf, sz); } - SHA1_Final(tsha1, &sha1ctx); + sha1_final(&sha1ctx, tsha1); return (memcmp(expected_sha1, tsha1, 20) == 0) ? 1 : 0; } diff --git a/src/sha1.c b/src/sha1.c deleted file mode 100644 index 02557ffe..00000000 --- a/src/sha1.c +++ /dev/null @@ -1,294 +0,0 @@ -/* -SHA-1 in C -By Steve Reid -100% Public Domain -Test Vectors (from FIPS PUB 180-1) -"abc" - A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D -"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 -A million repetitions of "a" - 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F -*/ - -/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ -/* #define SHA1HANDSOFF * Copies data before messing with it. */ - -#define SHA1HANDSOFF - -#include -#include - -/* for uint32_t */ -#include - -#include "sha1.h" - - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* blk0() and blk() perform the initial expand. */ -/* I got the idea of expanding during the round function from SSLeay */ -#if BYTE_ORDER == LITTLE_ENDIAN -#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) -#elif BYTE_ORDER == BIG_ENDIAN -#define blk0(i) block->l[i] -#else -#error "Endianness not defined!" -#endif -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - - -/* Hash a single 512-bit block. This is the core of the algorithm. */ - -void SHA1Transform( - uint32_t state[5], - const unsigned char buffer[64] -) -{ - uint32_t a, b, c, d, e; - - typedef union - { - unsigned char c[64]; - uint32_t l[16]; - } CHAR64LONG16; - -#ifdef SHA1HANDSOFF - CHAR64LONG16 block[1]; /* use array to appear as a pointer */ - - memcpy(block, buffer, 64); -#else - /* The following had better never be used because it causes the - * pointer-to-const buffer to be cast into a pointer to non-const. - * And the result is written through. I threw a "const" in, hoping - * this will cause a diagnostic. - */ - CHAR64LONG16 *block = (const CHAR64LONG16 *) buffer; -#endif - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a, b, c, d, e, 0); - R0(e, a, b, c, d, 1); - R0(d, e, a, b, c, 2); - R0(c, d, e, a, b, 3); - R0(b, c, d, e, a, 4); - R0(a, b, c, d, e, 5); - R0(e, a, b, c, d, 6); - R0(d, e, a, b, c, 7); - R0(c, d, e, a, b, 8); - R0(b, c, d, e, a, 9); - R0(a, b, c, d, e, 10); - R0(e, a, b, c, d, 11); - R0(d, e, a, b, c, 12); - R0(c, d, e, a, b, 13); - R0(b, c, d, e, a, 14); - R0(a, b, c, d, e, 15); - R1(e, a, b, c, d, 16); - R1(d, e, a, b, c, 17); - R1(c, d, e, a, b, 18); - R1(b, c, d, e, a, 19); - R2(a, b, c, d, e, 20); - R2(e, a, b, c, d, 21); - R2(d, e, a, b, c, 22); - R2(c, d, e, a, b, 23); - R2(b, c, d, e, a, 24); - R2(a, b, c, d, e, 25); - R2(e, a, b, c, d, 26); - R2(d, e, a, b, c, 27); - R2(c, d, e, a, b, 28); - R2(b, c, d, e, a, 29); - R2(a, b, c, d, e, 30); - R2(e, a, b, c, d, 31); - R2(d, e, a, b, c, 32); - R2(c, d, e, a, b, 33); - R2(b, c, d, e, a, 34); - R2(a, b, c, d, e, 35); - R2(e, a, b, c, d, 36); - R2(d, e, a, b, c, 37); - R2(c, d, e, a, b, 38); - R2(b, c, d, e, a, 39); - R3(a, b, c, d, e, 40); - R3(e, a, b, c, d, 41); - R3(d, e, a, b, c, 42); - R3(c, d, e, a, b, 43); - R3(b, c, d, e, a, 44); - R3(a, b, c, d, e, 45); - R3(e, a, b, c, d, 46); - R3(d, e, a, b, c, 47); - R3(c, d, e, a, b, 48); - R3(b, c, d, e, a, 49); - R3(a, b, c, d, e, 50); - R3(e, a, b, c, d, 51); - R3(d, e, a, b, c, 52); - R3(c, d, e, a, b, 53); - R3(b, c, d, e, a, 54); - R3(a, b, c, d, e, 55); - R3(e, a, b, c, d, 56); - R3(d, e, a, b, c, 57); - R3(c, d, e, a, b, 58); - R3(b, c, d, e, a, 59); - R4(a, b, c, d, e, 60); - R4(e, a, b, c, d, 61); - R4(d, e, a, b, c, 62); - R4(c, d, e, a, b, 63); - R4(b, c, d, e, a, 64); - R4(a, b, c, d, e, 65); - R4(e, a, b, c, d, 66); - R4(d, e, a, b, c, 67); - R4(c, d, e, a, b, 68); - R4(b, c, d, e, a, 69); - R4(a, b, c, d, e, 70); - R4(e, a, b, c, d, 71); - R4(d, e, a, b, c, 72); - R4(c, d, e, a, b, 73); - R4(b, c, d, e, a, 74); - R4(a, b, c, d, e, 75); - R4(e, a, b, c, d, 76); - R4(d, e, a, b, c, 77); - R4(c, d, e, a, b, 78); - R4(b, c, d, e, a, 79); - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Wipe variables */ - a = b = c = d = e = 0; -#ifdef SHA1HANDSOFF - memset(block, '\0', sizeof(block)); -#endif -} - - -/* SHA1Init - Initialize new context */ - -void SHA1Init( - SHA1_CTX * context -) -{ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* Run your data through this. */ - -void SHA1Update( - SHA1_CTX * context, - const unsigned char *data, - size_t len -) -{ - size_t i; - - size_t j; - - j = context->count[0]; - if ((context->count[0] += len << 3) < j) - context->count[1]++; - context->count[1] += (len >> 29); - j = (j >> 3) & 63; - if ((j + len) > 63) - { - memcpy(&context->buffer[j], data, (i = 64 - j)); - SHA1Transform(context->state, context->buffer); - for (; i + 63 < len; i += 64) - { - SHA1Transform(context->state, &data[i]); - } - j = 0; - } - else - i = 0; - memcpy(&context->buffer[j], &data[i], len - i); -} - - -/* Add padding and return the message digest. */ - -void SHA1Final( - unsigned char digest[20], - SHA1_CTX * context -) -{ - unsigned i; - - unsigned char finalcount[8]; - - unsigned char c; - -#if 0 /* untested "improvement" by DHR */ - /* Convert context->count to a sequence of bytes - * in finalcount. Second element first, but - * big-endian order within element. - * But we do it all backwards. - */ - unsigned char *fcp = &finalcount[8]; - - for (i = 0; i < 2; i++) - { - uint32_t t = context->count[i]; - - int j; - - for (j = 0; j < 4; t >>= 8, j++) - *--fcp = (unsigned char) t} -#else - for (i = 0; i < 8; i++) - { - finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ - } -#endif - c = 0200; - SHA1Update(context, &c, 1); - while ((context->count[0] & 504) != 448) - { - c = 0000; - SHA1Update(context, &c, 1); - } - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - for (i = 0; i < 20; i++) - { - digest[i] = (unsigned char) - ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); - } - /* Wipe variables */ - memset(context, '\0', sizeof(*context)); - memset(&finalcount, '\0', sizeof(finalcount)); -} - -void SHA1( - const unsigned char *str, - size_t len, - unsigned char *hash_out -) -{ - SHA1_CTX ctx; - size_t ii; - - SHA1Init(&ctx); - for (ii=0; ii - 100% Public Domain - */ - -#include "stdint.h" - -typedef struct -{ - uint32_t state[5]; - uint32_t count[2]; - unsigned char buffer[64]; -} SHA1_CTX; - -void SHA1Transform( - uint32_t state[5], - const unsigned char buffer[64] - ); - -void SHA1Init( - SHA1_CTX * context - ); - -void SHA1Update( - SHA1_CTX * context, - const unsigned char *data, - size_t len - ); - -void SHA1Final( - unsigned char digest[20], - SHA1_CTX * context - ); - -void SHA1( - const unsigned char *str, - size_t len, - unsigned char *hash_out); - -#endif /* SHA1_H */ diff --git a/src/sha512.c b/src/sha512.c deleted file mode 100644 index 8f7c59d1..00000000 --- a/src/sha512.c +++ /dev/null @@ -1,314 +0,0 @@ -/* LibTomCrypt, modular cryptographic library -- Tom St Denis - * - * LibTomCrypt is a library that provides various cryptographic - * algorithms in a highly modular and flexible manner. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org - */ - -#include "fixedint.h" -#include "sha512.h" - -/* the K array */ -static const uint64_t K[80] = { - UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), - UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc), - UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019), - UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118), - UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe), - UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2), - UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1), - UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694), - UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3), - UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65), - UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483), - UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5), - UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210), - UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4), - UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725), - UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70), - UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926), - UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df), - UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8), - UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b), - UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001), - UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30), - UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910), - UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8), - UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53), - UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8), - UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb), - UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3), - UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60), - UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec), - UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9), - UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b), - UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207), - UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178), - UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6), - UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b), - UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493), - UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c), - UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a), - UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817) -}; - -/* Various logical functions */ - -#define ROR64c(x, y) \ - ( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \ - ((x)<<((uint64_t)(64-((y)&UINT64_C(63)))))) & UINT64_C(0xFFFFFFFFFFFFFFFF)) - -#define STORE64H(x, y) \ - { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ - (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ - (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ - (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } - -#define LOAD64H(x, y) \ - { x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \ - (((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \ - (((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \ - (((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); } - - -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S(x, n) ROR64c(x, n) -#define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n)) -#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) -#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) -#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) -#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) -#ifndef MIN - #define MIN(x, y) ( ((x)<(y))?(x):(y) ) -#endif - -/* compress 1024-bits */ -static int sha512_compress(sha512_context *md, unsigned char *buf) -{ - uint64_t S[8], W[80], t0, t1; - int i; - - /* copy state into S */ - for (i = 0; i < 8; i++) { - S[i] = md->state[i]; - } - - /* copy the state into 1024-bits into W[0..15] */ - for (i = 0; i < 16; i++) { - LOAD64H(W[i], buf + (8*i)); - } - - /* fill W[16..79] */ - for (i = 16; i < 80; i++) { - W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; - } - -/* Compress */ - #define RND(a,b,c,d,e,f,g,h,i) \ - t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ - t1 = Sigma0(a) + Maj(a, b, c);\ - d += t0; \ - h = t0 + t1; - - for (i = 0; i < 80; i += 8) { - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); - } - - #undef RND - - - - /* feedback */ - for (i = 0; i < 8; i++) { - md->state[i] = md->state[i] + S[i]; - } - - return 0; -} - - -/** - Initialize the hash state - @param md The hash state you wish to initialize - @return 0 if successful -*/ -int sha512_init(sha512_context * md) { - if (md == NULL) return 1; - - md->curlen = 0; - md->length = 0; - md->state[0] = UINT64_C(0x6a09e667f3bcc908); - md->state[1] = UINT64_C(0xbb67ae8584caa73b); - md->state[2] = UINT64_C(0x3c6ef372fe94f82b); - md->state[3] = UINT64_C(0xa54ff53a5f1d36f1); - md->state[4] = UINT64_C(0x510e527fade682d1); - md->state[5] = UINT64_C(0x9b05688c2b3e6c1f); - md->state[6] = UINT64_C(0x1f83d9abfb41bd6b); - md->state[7] = UINT64_C(0x5be0cd19137e2179); - md->num_qwords = 8; - - return 0; -} - -/** - Process a block of memory though the hash - @param md The hash state - @param in The data to hash - @param inlen The length of the data (octets) - @return 0 if successful -*/ -int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen) -{ - size_t n; - size_t i; - int err; - if (md == NULL) return 1; - if (in == NULL) return 1; - if (md->curlen > sizeof(md->buf)) { - return 1; - } - while (inlen > 0) { - if (md->curlen == 0 && inlen >= 128) { - if ((err = sha512_compress (md, (unsigned char *)in)) != 0) { - return err; - } - md->length += 128 * 8; - in += 128; - inlen -= 128; - } else { - n = MIN(inlen, (128 - md->curlen)); - - for (i = 0; i < n; i++) { - md->buf[i + md->curlen] = in[i]; - } - - - md->curlen += n; - in += n; - inlen -= n; - if (md->curlen == 128) { - if ((err = sha512_compress (md, md->buf)) != 0) { - return err; - } - md->length += 8*128; - md->curlen = 0; - } - } - } - return 0; -} - -/** - Terminate the hash to get the digest - @param md The hash state - @param out [out] The destination of the hash (64 bytes) - @return 0 if successful -*/ -int sha512_final(sha512_context * md, unsigned char *out) -{ - int i; - - if (md == NULL) return 1; - if (out == NULL) return 1; - - if (md->curlen >= sizeof(md->buf)) { - return 1; - } - - /* increase the length of the message */ - md->length += md->curlen * UINT64_C(8); - - /* append the '1' bit */ - md->buf[md->curlen++] = (unsigned char)0x80; - - /* if the length is currently above 112 bytes we append zeros - * then compress. Then we can fall back to padding zeros and length - * encoding like normal. - */ - if (md->curlen > 112) { - while (md->curlen < 128) { - md->buf[md->curlen++] = (unsigned char)0; - } - sha512_compress(md, md->buf); - md->curlen = 0; - } - - /* pad upto 120 bytes of zeroes - * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash - * > 2^64 bits of data... :-) - */ - while (md->curlen < 120) { - md->buf[md->curlen++] = (unsigned char)0; - } - - /* store length */ - STORE64H(md->length, md->buf+120); - sha512_compress(md, md->buf); - - /* copy output */ - for (i = 0; i < md->num_qwords; i++) { - STORE64H(md->state[i], out+(8*i)); - } - - return 0; -} - -int sha512(const unsigned char *message, size_t message_len, unsigned char *out) -{ - sha512_context ctx; - int ret; - if ((ret = sha512_init(&ctx))) return ret; - if ((ret = sha512_update(&ctx, message, message_len))) return ret; - if ((ret = sha512_final(&ctx, out))) return ret; - return 0; -} - -int sha384_init(sha384_context * md) { - if (md == NULL) return 1; - - md->curlen = 0; - md->length = 0; - md->state[0] = UINT64_C(0xcbbb9d5dc1059ed8); - md->state[1] = UINT64_C(0x629a292a367cd507); - md->state[2] = UINT64_C(0x9159015a3070dd17); - md->state[3] = UINT64_C(0x152fecd8f70e5939); - md->state[4] = UINT64_C(0x67332667ffc00b31); - md->state[5] = UINT64_C(0x8eb44a8768581511); - md->state[6] = UINT64_C(0xdb0c2e0d64f98fa7); - md->state[7] = UINT64_C(0x47b5481dbefa4fa4); - md->num_qwords = 6; - - return 0; -} - -int sha384_final(sha384_context * md, unsigned char* out) -{ - return sha512_final(md, out); -} - -int sha384_update(sha384_context * md, const unsigned char *in, size_t inlen) -{ - return sha512_update(md, in, inlen); -} - -int sha384(const unsigned char *message, size_t message_len, unsigned char *out) -{ - sha384_context ctx; - int ret; - if ((ret = sha384_init(&ctx))) return ret; - if ((ret = sha384_update(&ctx, message, message_len))) return ret; - if ((ret = sha384_final(&ctx, out))) return ret; - return 0; -} diff --git a/src/sha512.h b/src/sha512.h deleted file mode 100644 index 72db47b5..00000000 --- a/src/sha512.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef SHA512_H -#define SHA512_H - -#include - -#include "fixedint.h" - -/* state */ -typedef struct sha512_context_ { - uint64_t length, state[8]; - size_t curlen; - unsigned char buf[128]; - int num_qwords; -} sha512_context; - -#define SHA512_DIGEST_LENGTH 64 - -int sha512_init(sha512_context * md); -int sha512_final(sha512_context * md, unsigned char *out); -int sha512_update(sha512_context * md, const unsigned char *in, size_t inlen); -int sha512(const unsigned char *message, size_t message_len, unsigned char *out); - -typedef sha512_context sha384_context; - -#define SHA384_DIGEST_LENGTH 48 - -int sha384_init(sha384_context * md); -int sha384_final(sha384_context * md, unsigned char *out); -int sha384_update(sha384_context * md, const unsigned char *in, size_t inlen); -int sha384(const unsigned char *message, size_t message_len, unsigned char *out); - -#endif From 4117b894f495a929c69073fba019be1998fa5f31 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 17 Jun 2024 19:58:23 +0200 Subject: [PATCH 086/117] Require libtatsu-1.0.3 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d2c7f32e..d0a052f8 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.6.0 LIMD_GLUE_VERSION=1.3.0 -LIBTATSU_VERSION=1.0.2 +LIBTATSU_VERSION=1.0.3 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 From a4cf7e2279f9d7ba0625b31bec2b43c957534dd3 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 19 Jun 2024 15:02:49 +0200 Subject: [PATCH 087/117] Updated README --- README.md | 223 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 178 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 3b525678..1af2d935 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,21 @@ ![](https://github.com/libimobiledevice/idevicerestore/actions/workflows/build.yml/badge.svg) +## Table of Contents +- [Features](#features) +- [Building](#building) + - [Prerequisites](#prerequisites) + - [Linux (Debian/Ubuntu based)](#linux-debianubuntu-based) + - [macOS](#macos) + - [Windows](#windows) + - [Configuring the source tree](#configuring-the-source-tree) + - [Building and installation](#building-and-installation) +- [Usage](#usage) +- [Contributing](#contributing) +- [Links](#links) +- [License](#license) +- [Credits](#credits) + ## Features The idevicerestore application is a full reimplementation of all granular steps @@ -33,56 +48,176 @@ Use with caution and make sure to backup your data before trying to restore. **In any case, usage is at your own risk.** -## Installation / Getting started - -### Debian / Ubuntu Linux +## Building + +### Prerequisites + +You need to have a working compiler (gcc/clang) and development environent +available. This project uses autotools for the build process, allowing to +have common build steps across different platforms. +Only the prerequisites differ and they are described in this section. + +#### Linux (Debian/Ubuntu based) + +* Install all required dependencies and build tools: + ```shell + sudo apt-get install \ + build-essential \ + pkg-config \ + checkinstall \ + git \ + autoconf \ + automake \ + libtool-bin \ + libreadline-dev \ + libusb-1.0-0-dev \ + libplist-dev \ + libimobiledevice-dev \ + libimobiledevice-glue-dev \ + libtatsu-dev \ + libcurl4-openssl-dev \ + libssl-dev \ + libzip-dev \ + zlib1g-dev + ``` + NOTE: [libtatsu](https://github.com/libimobiledevice/libtatsu) (and thus `libtatsu-dev`) + is a new library that was just published recently, you have to + [build it from source](https://github.com/libimobiledevice/libtatsu?tab=readme-ov-file#building). + Also, other `*-dev` packages might not be available for your distribution, + so you will have to build these packages on your own as well. + +#### macOS + +* Make sure the Xcode command line tools are installed. + + **Option 1**: + The easiest way to build and install `idevicerestore` for macOS is using + the following build script which will do the work for you, it will build + and install all required dependencies: + ```bash + mkdir -p limd-build + cd limd-build + curl -o ./limd-build-macos.sh -L https://is.gd/limdmacos + bash ./limd-build-macos.sh + ``` + Follow the prompts of the script and you should have a working `idevicerestore` + available. + + **Option 2**: + Use either [MacPorts](https://www.macports.org/) + or [Homebrew](https://brew.sh/) to install `automake`, `autoconf`, and `libtool`. + + Using MacPorts: + ```shell + sudo port install libtool autoconf automake + ``` + + Using Homebrew: + ```shell + brew install libtool autoconf automake + ``` + + `idevicerestore` has a few dependencies from the libimobiledevice project. + You will have to build and install the following: + * [libplist](https://github.com/libimobiledevice/libplist) + * [libimobiledevice-glue](https://github.com/libimobiledevice/libimobiledevice-glue) + * [libusbmuxd](https://github.com/libimobiledevice/libusbmuxd) + * [libimobiledevice](https://github.com/libimobiledevice/libimobiledevice) + * [libirecovery](https://github.com/libimobiledevice/libirecovery) + * [libtatsu](https://github.com/libimobiledevice/libtatsu) + + Check their `README.md` for building and installation instructions. + +#### Windows + +* Using [MSYS2](https://www.msys2.org/) is the official way of compiling this project on Windows. Download the MSYS2 installer + and follow the installation steps. + + It is recommended to use the _MSYS2 MinGW 64-bit_ shell. Run it and make sure the required dependencies are installed: + + ```shell + pacman -S base-devel \ + git \ + mingw-w64-x86_64-gcc \ + make \ + libtool \ + autoconf \ + automake-wrapper + ``` + NOTE: You can use a different shell and different compiler according to your needs. Adapt the above command accordingly. + + `idevicerestore` has a few dependencies from the libimobiledevice project. + You will have to build and install the following: + * [libplist](https://github.com/libimobiledevice/libplist) + * [libimobiledevice-glue](https://github.com/libimobiledevice/libimobiledevice-glue) + * [libusbmuxd](https://github.com/libimobiledevice/libusbmuxd) + * [libimobiledevice](https://github.com/libimobiledevice/libimobiledevice) + * [libirecovery](https://github.com/libimobiledevice/libirecovery) + * [libtatsu](https://github.com/libimobiledevice/libtatsu) + + Check their `README.md` for building and installation instructions. + + +### Configuring the source tree + +You can build the source code from a git checkout, or from a `.tar.bz2` release tarball from [Releases](https://github.com/libimobiledevice/idevicerestore/releases). +Before we can build it, the source tree has to be configured for building. The steps depend on where you got the source from. + +* **From git** + + If you haven't done already, clone the actual project repository and change into the directory. + ```shell + git clone https://github.com/libimobiledevice/idevicerestore.git + cd idevicerestore + ``` + + Configure the source tree for building: + ```shell + ./autogen.sh + ``` + +* **From release tarball (.tar.bz2)** + + When using an official [release tarball](https://github.com/libimobiledevice/idevicerestore/releases) (`idevicerestore-x.y.z.tar.bz2`) + the procedure is slightly different. + + Extract the tarball: + ```shell + tar xjf idevicerestore-x.y.z.tar.bz2 + cd idevicerestore-x.y.z + ``` + + Configure the source tree for building: + ```shell + ./configure + ``` + +Both `./configure` and `./autogen.sh` (which generates and calls `configure`) accept a few options, for example `--prefix` to allow +building for a different target folder. You can simply pass them like this: -First install all required dependencies and build tools: ```shell -sudo apt-get install \ - build-essential \ - pkg-config \ - checkinstall \ - git \ - autoconf \ - automake \ - libtool-bin \ - libreadline-dev \ - libusb-1.0-0-dev \ - libplist-dev \ - libimobiledevice-dev \ - libimobiledevice-glue-dev \ - libcurl4-openssl-dev \ - libssl-dev \ - libzip-dev \ - zlib1g-dev +./autogen.sh --prefix=/usr/local ``` - -Then clone, build and install [libirecovery](https://github.com/libimobiledevice/libirecovery.git) which is not yet packaged: +or ```shell -git clone https://github.com/libimobiledevice/libirecovery.git -cd libirecovery -./autogen.sh -make -sudo make install -cd .. +./configure --prefix=/usr/local ``` -If the configure processes indicates old or missing libraries, your distribution -might not have yet packaged the latest versions. In that case you will have to -clone [these libraries](https://github.com/libimobiledevice/) separately and repeat the process in order to proceed. - -Continue with cloning the actual project repository: -```shell -git clone https://github.com/libimobiledevice/idevicerestore.git -cd idevicerestore +Once the command is successful, the last few lines of output will look like this: ``` +[...] +config.status: creating config.h +config.status: config.h is unchanged +config.status: executing depfiles commands +config.status: executing libtool commands -Now you can build and install it: -```shell -./autogen.sh -make -sudo make install +Configuration for idevicerestore 1.1.0: +------------------------------------------- + + Install prefix: .........: /usr/local + + Now type 'make' to build idevicerestore 1.1.0, + and then 'make install' for installation. ``` **Important** @@ -142,8 +277,6 @@ Please make sure your contribution adheres to: * Try to split larger changes into individual commits of a common domain * Use your real name and a valid email address for your commits -We are still working on the guidelines so bear with us! - ## Links * Homepage: https://libimobiledevice.org/ @@ -166,4 +299,4 @@ iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc. This project is an independent software application and has not been authorized, sponsored, or otherwise approved by Apple Inc. -README Updated on: 2022-04-04 +README Updated on: 2024-06-19 From e0839878e760a752ebec838bc5227e32ba8650db Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 22 Jun 2024 15:36:38 +0200 Subject: [PATCH 088/117] restore: Remove `build_identity` from the parameters of the functions --- src/restore.c | 269 ++++++++++++++++++++++++++++++++------------------ src/restore.h | 9 +- 2 files changed, 178 insertions(+), 100 deletions(-) diff --git a/src/restore.c b/src/restore.c index efb03f93..d7462198 100644 --- a/src/restore.c +++ b/src/restore.c @@ -898,16 +898,21 @@ static void restore_asr_progress_cb(double progress, void* userdata) } } -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, plist_t build_identity) +int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device) { asr_client_t asr = NULL; - - info("About to send filesystem...\n"); - ipsw_archive_t ipsw_dummy = NULL; ipsw_file_handle_t file = NULL; char* fsname = NULL; - if (build_identity_get_component_path(build_identity, "OS", &fsname) < 0) { + + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + + info("About to send filesystem...\n"); + + if (build_identity_get_component_path(client->restore->build_identity, "OS", &fsname) < 0) { error("ERROR: Unable to get path for filesystem component\n"); return -1; } @@ -1072,7 +1077,7 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl return 0; } -int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, const char* component, const char* component_name) +int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, const char* component, const char* component_name) { unsigned int size = 0; unsigned char* data = NULL; @@ -1081,6 +1086,11 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie plist_t dict = NULL; restored_error_t restore_error = RESTORE_E_SUCCESS; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + if (component_name == NULL) { component_name = component; } @@ -1093,7 +1103,7 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie } } if (!path) { - if (build_identity_get_component_path(build_identity, component, &path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, component, &path) < 0) { error("ERROR: Unable to find %s path from build identity\n", component); return -1; } @@ -1136,7 +1146,7 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie return 0; } -int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) { char* llb_path = NULL; char* llb_filename = NULL; @@ -1156,6 +1166,11 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* plist_t firmware_files = NULL; int flash_version_1 = 0; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + info("About to send NORData...\n"); plist_t arguments = plist_dict_get_item(message, "Arguments"); @@ -1169,7 +1184,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* } } if (llb_path == NULL) { - if (build_identity_get_component_path(build_identity, "LLB", &llb_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, "LLB", &llb_path) < 0) { error("ERROR: Unable to get component path for LLB\n"); return -1; } @@ -1209,7 +1224,7 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* } else { info("Getting firmware manifest from build identity\n"); plist_dict_iter iter = NULL; - plist_t build_id_manifest = plist_dict_get_item(build_identity, "Manifest"); + plist_t build_id_manifest = plist_dict_get_item(client->restore->build_identity, "Manifest"); if (build_id_manifest) { plist_dict_new_iter(build_id_manifest, &iter); } @@ -1362,8 +1377,8 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* unsigned char* personalized_data = NULL; unsigned int personalized_size = 0; - if (build_identity_has_component(build_identity, "RestoreSEP") && - build_identity_get_component_path(build_identity, "RestoreSEP", &restore_sep_path) == 0) { + if (build_identity_has_component(client->restore->build_identity, "RestoreSEP") && + build_identity_get_component_path(client->restore->build_identity, "RestoreSEP", &restore_sep_path) == 0) { component = "RestoreSEP"; ret = extract_component(client->ipsw, restore_sep_path, &component_data, &component_size); free(restore_sep_path); @@ -1387,8 +1402,8 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* personalized_size = 0; } - if (build_identity_has_component(build_identity, "SEP") && - build_identity_get_component_path(build_identity, "SEP", &sep_path) == 0) { + if (build_identity_has_component(client->restore->build_identity, "SEP") && + build_identity_get_component_path(client->restore->build_identity, "SEP", &sep_path) == 0) { component = "SEP"; ret = extract_component(client->ipsw, sep_path, &component_data, &component_size); free(sep_path); @@ -1412,8 +1427,8 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* personalized_size = 0; } - if (build_identity_has_component(build_identity, "SepStage1") && - build_identity_get_component_path(build_identity, "SepStage1", &sep_path) == 0) { + if (build_identity_has_component(client->restore->build_identity, "SepStage1") && + build_identity_get_component_path(client->restore->build_identity, "SepStage1", &sep_path) == 0) { component = "SepStage1"; ret = extract_component(client->ipsw, sep_path, &component_data, &component_size); free(sep_path); @@ -1820,7 +1835,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned return res; } -static int restore_send_baseband_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +static int restore_send_baseband_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) { int res = -1; uint64_t bb_cert_id = 0; @@ -1834,6 +1849,11 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer char* bbfwtmp = NULL; plist_t dict = NULL; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + info("About to send BasebandData...\n"); // NOTE: this function is called 2 or 3 times! @@ -1870,7 +1890,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer plist_dict_set_item(parameters, "BbGoldCertId", plist_new_uint(bb_cert_id)); plist_dict_set_item(parameters, "BbSNUM", plist_new_data((const char*)bb_snum, bb_snum_size)); - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* create baseband request */ plist_t request = tss_request_new(NULL); @@ -1884,7 +1904,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer tss_request_add_common_tags(request, parameters, NULL); tss_request_add_baseband_tags(request, parameters, NULL); - plist_t node = plist_access_path(build_identity, 2, "Info", "FDRSupport"); + plist_t node = plist_access_path(client->restore->build_identity, 2, "Info", "FDRSupport"); if (node && plist_get_node_type(node) == PLIST_BOOLEAN) { uint8_t b = 0; plist_get_bool_val(node, &b); @@ -1911,7 +1931,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer } // get baseband firmware file path from build identity - plist_t bbfw_path = plist_access_path(build_identity, 4, "Manifest", "BasebandFirmware", "Info", "Path"); + plist_t bbfw_path = plist_access_path(client->restore->build_identity, 4, "Manifest", "BasebandFirmware", "Info", "Path"); if (!bbfw_path || plist_get_node_type(bbfw_path) != PLIST_STRING) { error("ERROR: Unable to get BasebandFirmware/Info/Path node\n"); plist_free(response); @@ -2011,7 +2031,7 @@ int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device) return 0; } -static int restore_send_image_data(restored_client_t restore, struct idevicerestore_client_t *client, plist_t build_identity, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k) +static int restore_send_image_data(restored_client_t restore, struct idevicerestore_client_t *client, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k) { restored_error_t restore_error; plist_t arguments; @@ -2024,6 +2044,11 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest char *image_name = NULL; int want_image_list = 0; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + arguments = plist_dict_get_item(message, "Arguments"); want_image_list = plist_dict_get_bool(arguments, image_list_k); node = plist_dict_get_item(arguments, "ImageName"); @@ -2051,7 +2076,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest data_dict = plist_new_dict(); } - build_id_manifest = plist_dict_get_item(build_identity, "Manifest"); + build_id_manifest = plist_dict_get_item(client->restore->build_identity, "Manifest"); if (build_id_manifest) { plist_dict_new_iter(build_id_manifest, &iter); } @@ -2083,7 +2108,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest if (!image_name) { info("Found %s component '%s'\n", image_type_k, component); } - build_identity_get_component_path(build_identity, component, &path); + build_identity_get_component_path(client->restore->build_identity, component, &path); if (path) { ret = extract_component(client->ipsw, path, &component_data, &component_size); } @@ -2155,7 +2180,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest return 0; } -static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { const char *comp_name = NULL; char *comp_path = NULL; @@ -2167,6 +2192,12 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id plist_t p_dgr = NULL; int ret; uint64_t chip_id = 0; + + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + plist_t node = plist_dict_get_item(p_info, "SE,ChipID"); if (node && plist_get_node_type(node) == PLIST_UINT) { plist_get_uint_val(node, &chip_id); @@ -2177,9 +2208,9 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id comp_name = "SE,UpdatePayload"; } else { info("WARNING: Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id); - if (build_identity_has_component(build_identity, "SE,UpdatePayload")) + if (build_identity_has_component(client->restore->build_identity, "SE,UpdatePayload")) comp_name = "SE,UpdatePayload"; - else if (build_identity_has_component(build_identity, "SE,Firmware")) + else if (build_identity_has_component(client->restore->build_identity, "SE,Firmware")) comp_name = "SE,Firmware"; else { error("ERROR: Neither 'SE,Firmware' nor 'SE,UpdatePayload' found in build identity.\n"); @@ -2196,7 +2227,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id return NULL; } - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2220,7 +2251,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add SE,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2255,7 +2286,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id return response; } -static plist_t restore_get_savage_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_savage_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = NULL; char *comp_path = NULL; @@ -2267,6 +2298,11 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + /* create Savage request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2277,7 +2313,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add Savage,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2310,7 +2346,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc } /* now get actual component data */ - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); free(comp_name); return NULL; @@ -2346,7 +2382,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc return response; } -static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = NULL; char *comp_path = NULL; @@ -2357,6 +2393,11 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + /* create Yonkers request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2369,7 +2410,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add Yonkers,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2401,7 +2442,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru error("ERROR: No 'Yonkers,Ticket' in TSS response, this might not work\n"); } - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); free(comp_name); return NULL; @@ -2430,7 +2471,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru return response; } -static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; @@ -2444,6 +2485,11 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + /* create Rose request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2455,7 +2501,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); if (client->image4supported) { @@ -2501,7 +2547,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct } comp_name = "Rap,RTKitOS"; - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2525,8 +2571,8 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct } comp_name = "Rap,RestoreRTKitOS"; - if (build_identity_has_component(build_identity, comp_name)) { - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_has_component(client->restore->build_identity, comp_name)) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; @@ -2577,7 +2623,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct return response; } -static plist_t restore_get_veridian_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_veridian_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = "BMU,FirmwareMap"; char *comp_path = NULL; @@ -2588,6 +2634,11 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + /* create Veridian request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2599,7 +2650,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add BMU,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2624,7 +2675,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str error("ERROR: No 'BMU,Ticket' in TSS response, this might not work\n"); } - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2653,7 +2704,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str return NULL; } - plist_t fw_map_digest = plist_access_path(build_identity, 3, "Manifest", comp_name, "Digest"); + plist_t fw_map_digest = plist_access_path(client->restore->build_identity, 3, "Manifest", comp_name, "Digest"); if (!fw_map_digest) { plist_free(fw_map); error("ERROR: Unable to get Digest for '%s' component\n", comp_name); @@ -2673,7 +2724,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str return response; } -static plist_t restore_get_generic_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +static plist_t restore_get_generic_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { plist_t request = NULL; plist_t response = NULL; @@ -2728,7 +2779,7 @@ static plist_t restore_get_generic_firmware_data(restored_client_t restore, stru return response; } -static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info) +static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = "Baobab,TCON"; char *comp_path = NULL; @@ -2739,6 +2790,11 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct plist_t response = NULL; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + /* create Baobab request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2750,7 +2806,7 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); /* add Baobab,* tags from info dictionary to parameters */ plist_dict_merge(¶meters, p_info); @@ -2775,7 +2831,7 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct error("ERROR: No 'Baobab,Ticket' in TSS response, this might not work\n"); } - if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2797,7 +2853,7 @@ 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) +static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) { char comp_name[64]; char *comp_path = NULL; @@ -2813,6 +2869,11 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct uint32_t tag = 0; int ret; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + /* create Timer request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2823,7 +2884,7 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct parameters = plist_new_dict(); /* add manifest for current build_identity to parameters */ - tss_parameters_add_from_manifest(parameters, build_identity, true); + tss_parameters_add_from_manifest(parameters, client->restore->build_identity, true); plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); if (client->image4supported) { @@ -2902,8 +2963,8 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct } 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) { + if (build_identity_has_component(client->restore->build_identity, comp_name)) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2930,8 +2991,8 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct } 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) { + if (build_identity_has_component(client->restore->build_identity, comp_name)) { + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; @@ -2982,12 +3043,17 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct return response; } -static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info, plist_t arguments) +static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { plist_t parameters = NULL; plist_t request = NULL; plist_t response = NULL; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return NULL; + } + plist_t p_updater_name = plist_dict_get_item(arguments, "MessageArgUpdaterName"); const char* s_updater_name = plist_get_string_ptr(p_updater_name, NULL); @@ -3019,7 +3085,7 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str for (i = 0; i < plist_array_get_size(build_identity_tags); i++) { plist_t node = plist_array_get_item(build_identity_tags, i); const char* key = plist_get_string_ptr(node, NULL); - plist_t item = plist_dict_get_item(build_identity, key); + plist_t item = plist_dict_get_item(client->restore->build_identity, key); if (item) { plist_dict_set_item(parameters, key, plist_copy(item)); } @@ -3034,10 +3100,10 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1)); } if (!plist_dict_get_item(parameters, "ApChipID")) { - plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL); + plist_dict_copy_uint(parameters, client->restore->build_identity, "ApChipID", NULL); } if (!plist_dict_get_item(parameters, "ApBoardID")) { - plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL); + plist_dict_copy_uint(parameters, client->restore->build_identity, "ApBoardID", NULL); } /* add device generated request data to parameters */ @@ -3072,7 +3138,7 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str return response; } -static int restore_send_firmware_updater_preflight(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +static int restore_send_firmware_updater_preflight(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) { plist_t dict = NULL; int restore_error; @@ -3096,7 +3162,7 @@ static int restore_send_firmware_updater_preflight(restored_client_t restore, st return 0; } -static int restore_send_firmware_updater_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message) +static int restore_send_firmware_updater_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) { plist_t arguments; plist_t p_type, p_updater_name, p_loop_count, p_info; @@ -3107,6 +3173,11 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct char *s_updater_name = NULL; int restore_error; + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + if (idevicerestore_debug) { debug("DEBUG: %s: Got FirmwareUpdaterData request:\n", __func__); debug_plist(message); @@ -3153,7 +3224,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct plist_get_string_val(p_updater_name, &s_updater_name); if (strcmp(s_updater_name, "SE") == 0) { - fwdict = restore_get_se_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_se_firmware_data(restore, client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get SE firmware data\n", __func__); goto error_out; @@ -3163,59 +3234,59 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct plist_t p_info2 = plist_dict_get_item(p_info, "YonkersDeviceInfo"); if (p_info2 && plist_get_node_type(p_info2) == PLIST_DICT) { fwtype = "Yonkers"; - fwdict = restore_get_yonkers_firmware_data(restore, client, build_identity, p_info2); + fwdict = restore_get_yonkers_firmware_data(restore, client, p_info2); } else { - fwdict = restore_get_savage_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_savage_firmware_data(restore, client, p_info); } if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, fwtype); goto error_out; } } else if (strcmp(s_updater_name, "Rose") == 0) { - fwdict = restore_get_rose_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_rose_firmware_data(restore, client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get Rose firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "T200") == 0) { - fwdict = restore_get_veridian_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_veridian_firmware_data(restore, client, p_info); if (fwdict == NULL) { error("ERROR: %s: Couldn't get Veridian firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "AppleTCON") == 0) { - fwdict = restore_get_tcon_firmware_data(restore, client, build_identity, p_info); + fwdict = restore_get_tcon_firmware_data(restore, client, p_info); if (fwdict == NULL) { error("ERROR: %s: Couldn't get AppleTCON firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "PS190") == 0) { - fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_generic_firmware_data(restore, client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get PCON1 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); + fwdict = restore_get_timer_firmware_data(restore, client, p_info); if (fwdict == NULL) { error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); goto error_out; } } else if ((strcmp(s_updater_name, "Cryptex1") == 0) || (strcmp(s_updater_name, "Cryptex1LocalPolicy") == 0)) { - fwdict = restore_get_cryptex1_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_cryptex1_firmware_data(restore, client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else if (strcmp(s_updater_name, "Ace3") == 0) { - fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_generic_firmware_data(restore, client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else { error("ERROR: %s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); - fwdict = restore_get_generic_firmware_data(restore, client, build_identity, p_info, arguments); + fwdict = restore_get_generic_firmware_data(restore, client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; @@ -3246,12 +3317,17 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct return -1; } -static int restore_send_receipt_manifest(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity) +static int restore_send_receipt_manifest(restored_client_t restore, struct idevicerestore_client_t* client) { plist_t dict; int restore_error; - plist_t manifest = plist_dict_get_item(build_identity, "Manifest"); + if (!client || !client->restore || !client->restore->build_identity) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + + plist_t manifest = plist_dict_get_item(client->restore->build_identity, "Manifest"); if (!manifest) { error("failed to get Manifest node from build_identity"); goto error_out; @@ -3379,7 +3455,7 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch return ret; } -static int restore_send_bootability_bundle_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message, idevice_t device) +static int restore_send_bootability_bundle_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message, idevice_t device) { if (idevicerestore_debug) { debug("DEBUG: %s: Got BootabilityBundle request:\n", __func__); @@ -3563,7 +3639,7 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi return 0; } -int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity) +int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) { if (idevicerestore_debug) { debug("DEBUG: %s: Got PersonalizedBootObjectV3 request:\n", __func__); @@ -3593,7 +3669,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i info("About to send %s...\n", component); if (strcmp(image_name, "__GlobalManifest__") == 0) { - int ret = extract_global_manifest(client, build_identity, NULL, &data, &size); + int ret = extract_global_manifest(client, client->restore->build_identity, NULL, &data, &size); if (ret != 0) { return -1; } @@ -3674,7 +3750,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i return 0; } -int restore_send_source_boot_object_v4(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg, plist_t build_identity) +int restore_send_source_boot_object_v4(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) { if (idevicerestore_debug) { debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__); @@ -3718,7 +3794,7 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice return -1; } - path = extract_global_manifest_path(build_identity, variant); + path = extract_global_manifest_path(client->restore->build_identity, variant); } else if (strcmp(image_name, "__RestoreVersion__") == 0) { path = strdup("RestoreVersion.plist"); } else if (strcmp(image_name, "__SystemVersion__") == 0) { @@ -3842,7 +3918,7 @@ int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_ return 0; } -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity) +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message) { plist_t node = NULL; @@ -3854,7 +3930,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem if (!strcmp(type, "SystemImageData")) { - if(restore_send_filesystem(client, device, build_identity) < 0) { + if(restore_send_filesystem(client, device) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -3868,14 +3944,14 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } else if (!strcmp(type, "PersonalizedBootObjectV3")) { - if (restore_send_personalized_boot_object_v3(restore, client, message, build_identity) < 0) { + if (restore_send_personalized_boot_object_v3(restore, client, message) < 0) { error("ERROR: Unable to send PersonalizedBootObjectV3\n"); return -1; } } else if (!strcmp(type, "SourceBootObjectV4")) { - if (restore_send_source_boot_object_v4(restore, client, message, build_identity) < 0) { + if (restore_send_source_boot_object_v4(restore, client, message) < 0) { error("ERROR: Unable to send SourceBootObjectV4\n"); return -1; } @@ -3890,7 +3966,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem else if (!strcmp(type, "RecoveryOSASRImage")) { - if(restore_send_filesystem(client, device, build_identity) < 0) { + if(restore_send_filesystem(client, device) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -3913,28 +3989,28 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } // send KernelCache else if (!strcmp(type, "KernelCache")) { - if (restore_send_component(restore, client, build_identity, "KernelCache", NULL) < 0) { + if (restore_send_component(restore, client, "KernelCache", NULL) < 0) { error("ERROR: Unable to send kernelcache\n"); return -1; } } else if (!strcmp(type, "DeviceTree")) { - if (restore_send_component(restore, client, build_identity, "DeviceTree", NULL) < 0) { + if (restore_send_component(restore, client, "DeviceTree", NULL) < 0) { error("ERROR: Unable to send DeviceTree\n"); return -1; } } else if (!strcmp(type, "SystemImageRootHash")) { - if (restore_send_component(restore, client, build_identity, "SystemVolume", type) < 0) { + if (restore_send_component(restore, client, "SystemVolume", type) < 0) { error("ERROR: Unable to send SystemImageRootHash data\n"); return -1; } } else if (!strcmp(type, "SystemImageCanonicalMetadata")) { - if (restore_send_component(restore, client, build_identity, "Ap,SystemVolumeCanonicalMetadata", type) < 0) { + if (restore_send_component(restore, client, "Ap,SystemVolumeCanonicalMetadata", type) < 0) { error("ERROR: Unable to send SystemImageCanonicalMetadata data\n"); return -1; } @@ -3942,7 +4018,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev else if (!strcmp(type, "NORData")) { if((client->flags & FLAG_EXCLUDE) == 0) { - if(restore_send_nor(restore, client, build_identity, message) < 0) { + if(restore_send_nor(restore, client, message) < 0) { error("ERROR: Unable to send NOR data\n"); return -1; } @@ -3953,7 +4029,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } else if (!strcmp(type, "BasebandData")) { - if(restore_send_baseband_data(restore, client, build_identity, message) < 0) { + if(restore_send_baseband_data(restore, client, message) < 0) { error("ERROR: Unable to send baseband data\n"); return -1; } @@ -3967,49 +4043,49 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } else if (!strcmp(type, "FUDData")) { - if(restore_send_image_data(restore, client, build_identity, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) { + if(restore_send_image_data(restore, client, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) { error("ERROR: Unable to send FUD data\n"); return -1; } } else if (!strcmp(type, "FirmwareUpdaterPreflight")) { - if(restore_send_firmware_updater_preflight(restore, client, build_identity, message) < 0) { + if(restore_send_firmware_updater_preflight(restore, client, message) < 0) { error("ERROR: Unable to send FirmwareUpdaterPreflight\n"); return -1; } } else if (!strcmp(type, "FirmwareUpdaterData")) { - if(restore_send_firmware_updater_data(restore, client, build_identity, message) < 0) { + if(restore_send_firmware_updater_data(restore, client, message) < 0) { error("ERROR: Unable to send FirmwareUpdater data\n"); return -1; } } else if (!strcmp(type, "PersonalizedData")) { - if(restore_send_image_data(restore, client, build_identity, message, "ImageList", NULL, "ImageData") < 0) { + if(restore_send_image_data(restore, client, message, "ImageList", NULL, "ImageData") < 0) { error("ERROR: Unable to send Personalized data\n"); return -1; } } else if (!strcmp(type, "EANData")) { - if(restore_send_image_data(restore, client, build_identity, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) { + if(restore_send_image_data(restore, client, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) { error("ERROR: Unable to send Personalized data\n"); return -1; } } else if (!strcmp(type, "BootabilityBundle")) { - if (restore_send_bootability_bundle_data(restore, client, build_identity, message, device) < 0) { + if (restore_send_bootability_bundle_data(restore, client, message, device) < 0) { error("ERROR: Unable to send BootabilityBundle data\n"); return -1; } } else if (!strcmp(type, "ReceiptManifest")) { - if (restore_send_receipt_manifest(restore, client, build_identity) < 0) { + if (restore_send_receipt_manifest(restore, client) < 0) { error("ERROR: Unable to send ReceiptManifest data\n"); return -1; } @@ -4157,6 +4233,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit } info("Device %s has successfully entered restore mode\n", client->udid); + client->restore->build_identity = build_identity; restore = client->restore->client; device = client->restore->device; @@ -4456,7 +4533,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // files sent to the server by the client. these data requests include // SystemImageData, RootTicket, KernelCache, NORData and BasebandData requests if (!strcmp(type, "DataRequestMsg")) { - err = restore_handle_data_request_msg(client, device, restore, message, build_identity); + err = restore_handle_data_request_msg(client, device, restore, message); } // restore logs are available if a previous restore failed diff --git a/src/restore.h b/src/restore.h index 765f3746..228de741 100644 --- a/src/restore.h +++ b/src/restore.h @@ -40,6 +40,7 @@ struct restore_client_t { unsigned int operation; uint64_t protocol_version; restored_client_t client; + plist_t build_identity; }; int restore_check_mode(struct idevicerestore_client_t* client); @@ -51,13 +52,13 @@ int restore_reboot(struct idevicerestore_client_t* client); const char* restore_progress_string(unsigned int operation); int restore_handle_status_msg(restored_client_t client, plist_t msg); int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t msg); -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message, plist_t build_identity); -int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message); +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message); +int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message); int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client); -int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, const char* component, const char* component_name); +int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, const char* component, const char* component_name); int restore_device(struct idevicerestore_client_t* client, plist_t build_identity); int restore_open_with_timeout(struct idevicerestore_client_t* client); -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device, plist_t build_identity); +int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device); int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device); #ifdef __cplusplus From de1d17df224bffa4ae40e8b052c57d3af4f83dfd Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 22 Jun 2024 17:08:15 +0200 Subject: [PATCH 089/117] restore: Remove `device` from the parameters of the functions --- src/restore.c | 42 ++++++++++++++++++++++++++---------------- src/restore.h | 6 +++--- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/restore.c b/src/restore.c index d7462198..6ac70b44 100644 --- a/src/restore.c +++ b/src/restore.c @@ -781,7 +781,7 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) return result; } -static int restore_handle_baseband_updater_output_data(restored_client_t restore, struct idevicerestore_client_t* client, idevice_t device, plist_t msg) +static int restore_handle_baseband_updater_output_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) { int result = -1; plist_t node = plist_dict_get_item(msg, "DataPort"); @@ -793,9 +793,14 @@ static int restore_handle_baseband_updater_output_data(restored_client_t restore idevice_connection_t connection = NULL; idevice_error_t device_error = IDEVICE_E_SUCCESS; + if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + debug("Connecting to baseband updater data port\n"); while (--attempts > 0) { - device_error = idevice_connect(device, data_port, &connection); + device_error = idevice_connect(client->restore->device, data_port, &connection); if (device_error == IDEVICE_E_SUCCESS) { break; } @@ -898,14 +903,14 @@ static void restore_asr_progress_cb(double progress, void* userdata) } } -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device) +int restore_send_filesystem(struct idevicerestore_client_t* client) { asr_client_t asr = NULL; ipsw_archive_t ipsw_dummy = NULL; ipsw_file_handle_t file = NULL; char* fsname = NULL; - if (!client || !client->restore || !client->restore->build_identity) { + if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) { error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); return -1; } @@ -931,7 +936,7 @@ int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t de free(fsname); } - if (asr_open_with_timeout(device, &asr) < 0) { + if (asr_open_with_timeout(client->restore->device, &asr) < 0) { ipsw_file_close(file); ipsw_close(ipsw_dummy); error("ERROR: Unable to connect to ASR\n"); @@ -2006,7 +2011,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer return res; } -int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device) +int restore_send_fdr_trust_data(restored_client_t restore) { restored_error_t restore_error; plist_t dict; @@ -3455,7 +3460,7 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch return ret; } -static int restore_send_bootability_bundle_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message, idevice_t device) +static int restore_send_bootability_bundle_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) { if (idevicerestore_debug) { debug("DEBUG: %s: Got BootabilityBundle request:\n", __func__); @@ -3471,9 +3476,14 @@ static int restore_send_bootability_bundle_data(restored_client_t restore, struc idevice_connection_t connection = NULL; idevice_error_t device_error = IDEVICE_E_SUCCESS; + if (!client || !client->restore || !client->restore->build_identity || !client->restore->device) { + error("ERROR: %s: idevicerestore client not initialized?!\n", __func__); + return -1; + } + debug("Connecting to BootabilityBundle data port\n"); while (--attempts > 0) { - device_error = idevice_connect(device, data_port, &connection); + device_error = idevice_connect(client->restore->device, data_port, &connection); if (device_error == IDEVICE_E_SUCCESS) { break; } @@ -3918,7 +3928,7 @@ int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_ return 0; } -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message) +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, restored_client_t restore, plist_t message) { plist_t node = NULL; @@ -3930,7 +3940,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem if (!strcmp(type, "SystemImageData")) { - if(restore_send_filesystem(client, device) < 0) { + if(restore_send_filesystem(client) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -3966,7 +3976,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev // this request is sent when restored is ready to receive the filesystem else if (!strcmp(type, "RecoveryOSASRImage")) { - if(restore_send_filesystem(client, device) < 0) { + if(restore_send_filesystem(client) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -4036,7 +4046,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } else if (!strcmp(type, "FDRTrustData")) { - if(restore_send_fdr_trust_data(restore, device) < 0) { + if(restore_send_fdr_trust_data(restore) < 0) { error("ERROR: Unable to send FDR Trust data\n"); return -1; } @@ -4078,7 +4088,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } else if (!strcmp(type, "BootabilityBundle")) { - if (restore_send_bootability_bundle_data(restore, client, message, device) < 0) { + if (restore_send_bootability_bundle_data(restore, client, message) < 0) { error("ERROR: Unable to send BootabilityBundle data\n"); return -1; } @@ -4092,7 +4102,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev } else if (!strcmp(type, "BasebandUpdaterOutputData")) { - if (restore_handle_baseband_updater_output_data(restore, client, device, message) < 0) { + if (restore_handle_baseband_updater_output_data(restore, client, message) < 0) { error("ERROR: Unable to send BasebandUpdaterOutputData data\n"); return -1; } @@ -4533,7 +4543,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // files sent to the server by the client. these data requests include // SystemImageData, RootTicket, KernelCache, NORData and BasebandData requests if (!strcmp(type, "DataRequestMsg")) { - err = restore_handle_data_request_msg(client, device, restore, message); + err = restore_handle_data_request_msg(client, restore, message); } // restore logs are available if a previous restore failed @@ -4610,7 +4620,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // baseband updater output data request else if (!strcmp(type, "BasebandUpdaterOutputData")) { - err = restore_handle_baseband_updater_output_data(restore, client, device, message); + err = restore_handle_baseband_updater_output_data(restore, client, message); } // there might be some other message types i'm not aware of, but I think diff --git a/src/restore.h b/src/restore.h index 228de741..851b1813 100644 --- a/src/restore.h +++ b/src/restore.h @@ -52,14 +52,14 @@ int restore_reboot(struct idevicerestore_client_t* client); const char* restore_progress_string(unsigned int operation); int restore_handle_status_msg(restored_client_t client, plist_t msg); int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t msg); -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idevice_t device, restored_client_t restore, plist_t message); +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, restored_client_t restore, plist_t message); int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message); int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client); int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, const char* component, const char* component_name); int restore_device(struct idevicerestore_client_t* client, plist_t build_identity); int restore_open_with_timeout(struct idevicerestore_client_t* client); -int restore_send_filesystem(struct idevicerestore_client_t* client, idevice_t device); -int restore_send_fdr_trust_data(restored_client_t restore, idevice_t device); +int restore_send_filesystem(struct idevicerestore_client_t* client); +int restore_send_fdr_trust_data(restored_client_t restore); #ifdef __cplusplus } From 28c1dab3c2c631d8bea7d0a08aa48a1e11da7eff Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 24 Jun 2024 12:42:22 +0200 Subject: [PATCH 090/117] Add support for iOS 18 restore process --- src/asr.c | 15 +- src/asr.h | 4 +- src/common.c | 36 +- src/common.h | 1 + src/idevicerestore.c | 5 +- src/restore.c | 804 +++++++++++++++++++++++++++++++++++++------ src/restore.h | 16 +- 7 files changed, 750 insertions(+), 131 deletions(-) diff --git a/src/asr.c b/src/asr.c index aadf25a1..b150e852 100644 --- a/src/asr.c +++ b/src/asr.c @@ -40,7 +40,6 @@ #define ASR_VERSION 1 #define ASR_STREAM_ID 1 -#define ASR_PORT 12345 #define ASR_BUFFER_SIZE 65536 #define ASR_FEC_SLICE_STRIDE 40 #define ASR_PACKETS_PER_FEC 25 @@ -48,7 +47,7 @@ #define ASR_PAYLOAD_CHUNK_SIZE 131072 #define ASR_CHECKSUM_CHUNK_SIZE 131072 -int asr_open_with_timeout(idevice_t device, asr_client_t* asr) +int asr_open_with_timeout(idevice_t device, asr_client_t* asr, uint16_t port) { int i = 0; int attempts = 10; @@ -61,9 +60,13 @@ int asr_open_with_timeout(idevice_t device, asr_client_t* asr) return -1; } - debug("Connecting to ASR\n"); + if (port == 0) { + port = ASR_DEFAULT_PORT; + } + debug("Connecting to ASR on port %u\n", port); + for (i = 1; i <= attempts; i++) { - device_error = idevice_connect(device, ASR_PORT, &connection); + device_error = idevice_connect(device, port, &connection); if (device_error == IDEVICE_E_SUCCESS) { break; } @@ -358,7 +361,7 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) sendsize += 20; } if (asr_send_buffer(asr, data, sendsize) < 0) { - error("ERROR: Unable to send filesystem payload\n"); + error("Unable to send filesystem payload chunk, retrying...\n"); retry--; continue; } @@ -374,5 +377,5 @@ int asr_send_payload(asr_client_t asr, ipsw_file_handle_t file) } free(data); - return 0; + return (i == 0) ? 0 : -1; } diff --git a/src/asr.h b/src/asr.h index 0d9534c2..4473fbb4 100644 --- a/src/asr.h +++ b/src/asr.h @@ -30,6 +30,8 @@ extern "C" { #include +#define ASR_DEFAULT_PORT 12345 + typedef void (*asr_progress_cb_t)(double, void*); struct asr_client { @@ -44,7 +46,7 @@ typedef struct asr_client *asr_client_t; struct ipsw_file_handle; typedef struct ipsw_file_handle* ipsw_file_handle_t; -int asr_open_with_timeout(idevice_t device, asr_client_t* asr); +int asr_open_with_timeout(idevice_t device, asr_client_t* asr, uint16_t port); void asr_set_progress_callback(asr_client_t asr, asr_progress_cb_t, void* userdata); int asr_send(asr_client_t asr, plist_t data); int asr_receive(asr_client_t asr, plist_t* data); diff --git a/src/common.c b/src/common.c index e5ee07b9..80d82560 100644 --- a/src/common.c +++ b/src/common.c @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef WIN32 #include @@ -79,17 +80,31 @@ static int info_disabled = 0; static int error_disabled = 0; static int debug_disabled = 0; +static mutex_t log_mutex; +static thread_once_t init_once = THREAD_ONCE_INIT; + +static void _log_init(void) +{ + printf("******** _log_init ********\n"); + mutex_init(&log_mutex); +} + void info(const char* format, ...) { if (info_disabled) return; + thread_once(&init_once, _log_init); + mutex_lock(&log_mutex); va_list vargs; va_start(vargs, format); vfprintf((info_stream) ? info_stream : stdout, format, vargs); va_end(vargs); + mutex_unlock(&log_mutex); } void error(const char* format, ...) { + thread_once(&init_once, _log_init); + mutex_lock(&log_mutex); va_list vargs, vargs2; va_start(vargs, format); va_copy(vargs2, vargs); @@ -99,6 +114,7 @@ void error(const char* format, ...) vfprintf((error_stream) ? error_stream : stderr, format, vargs2); } va_end(vargs2); + mutex_unlock(&log_mutex); } void debug(const char* format, ...) @@ -107,10 +123,13 @@ void debug(const char* format, ...) if (!idevicerestore_debug) { return; } + thread_once(&init_once, _log_init); + mutex_lock(&log_mutex); va_list vargs; va_start(vargs, format); vfprintf((debug_stream) ? debug_stream : stderr, format, vargs); va_end(vargs); + mutex_unlock(&log_mutex); } void idevicerestore_set_info_stream(FILE* strm) @@ -227,9 +246,9 @@ void debug_plist(plist_t plist) { char* data = NULL; plist_to_xml(plist, &data, &size); if (size <= MAX_PRINT_LEN) - info("%s:printing %i bytes plist:\n%s", __FILE__, size, data); + info("printing %i bytes plist:\n%s", size, data); else - info("%s:supressed printing %i bytes plist...\n", __FILE__, size); + info("supressed printing %i bytes plist...\n", size); free(data); } @@ -239,13 +258,13 @@ void print_progress_bar(double progress) { int i = 0; if(progress < 0) return; if(progress > 100) progress = 100; - info("\r["); + fprintf((info_stream) ? info_stream : stdout, "\r["); for(i = 0; i < 50; i++) { - if(i < progress / 2) info("="); - else info(" "); + if(i < progress / 2) fprintf((info_stream) ? info_stream : stdout, "="); + else fprintf((info_stream) ? info_stream : stdout, " "); } - info("] %5.1f%%", progress); - if(progress >= 100) info("\n"); + fprintf((info_stream) ? info_stream : stdout, "] %5.1f%%", progress); + if(progress >= 100) fprintf((info_stream) ? info_stream : stdout, "\n"); fflush((info_stream) ? info_stream : stdout); #endif } @@ -464,6 +483,8 @@ char *get_temp_filename(const char *prefix) void idevicerestore_progress(struct idevicerestore_client_t* client, int step, double progress) { + thread_once(&init_once, _log_init); + mutex_lock(&log_mutex); if(client && client->progress_cb) { client->progress_cb(step, progress, client->progress_cb_data); } else { @@ -472,6 +493,7 @@ void idevicerestore_progress(struct idevicerestore_client_t* client, int step, d print_progress_bar(100.0 * progress); } } + mutex_unlock(&log_mutex); } #ifndef HAVE_STRSEP diff --git a/src/common.h b/src/common.h index 766a3853..8085a1a1 100644 --- a/src/common.h +++ b/src/common.h @@ -134,6 +134,7 @@ struct idevicerestore_client_t { char* restore_variant; char* filesystem; int delete_fs; + int async_err; }; extern struct idevicerestore_mode_t idevicerestore_modes[]; diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 309f2b69..8de9186d 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1514,10 +1514,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } } - info("DONE\n"); - if (result == 0) { + info("DONE\n"); idevicerestore_progress(client, RESTORE_NUM_STEPS-1, 1.0); + } else { + info("RESTORE FAILED\n"); } if (build_identity_needs_free) diff --git a/src/restore.c b/src/restore.c index 6ac70b44..a62886df 100644 --- a/src/restore.c +++ b/src/restore.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #ifdef HAVE_REVERSE_PROXY #include #else @@ -39,6 +41,7 @@ #include #include #include +#include #include "idevicerestore.h" #include "asr.h" @@ -633,6 +636,101 @@ const char* restore_progress_string(unsigned int operation) } } +struct restored_service_client { + +}; + +#define SERVICE_TYPE_RESTORED 1 +#define SERVICE_TYPE_PLIST 2 + +typedef struct restore_service_client { + void* client; + int type; +} *restore_service_client_t; + +static void* _restore_get_service_client_for_data_request(struct idevicerestore_client_t *client, plist_t message) +{ + if (!client || !client->restore || !client->restore->client || !PLIST_IS_DICT(message)) return NULL; + restore_service_client_t service = (restore_service_client_t)malloc(sizeof(struct restore_service_client)); + if (!plist_dict_get_item(message, "DataPort")) { + service->client = client->restore->client; + service->type = SERVICE_TYPE_RESTORED; + return service; + } + plist_t data_type = plist_dict_get_item(message, "DataType"); + uint16_t data_port = plist_dict_get_uint(message, "DataPort"); + const char* data_type_str = plist_get_string_ptr(data_type, NULL); + + struct lockdownd_service_descriptor svcdesc = { + data_port, + 0, + (char*)data_type_str + }; + property_list_service_client_t plclient = NULL; + info("Connecting to %s data port %u\n", data_type_str, data_port); + if (property_list_service_client_new(client->restore->device, &svcdesc, &plclient) != PROPERTY_LIST_SERVICE_E_SUCCESS) { + error("ERROR: Failed to start service connection for %s on port %u\n", data_type_str, data_port); + free(service); + return NULL; + } + service->client = plclient; + service->type = SERVICE_TYPE_PLIST; + + return service; +} + +static int _restore_service_send(restore_service_client_t service, plist_t plist, plist_format_t fmt) +{ + if (!service) { + return -1; + } + switch (service->type) { + case SERVICE_TYPE_RESTORED: + return restored_send((restored_client_t)service->client, plist); + case SERVICE_TYPE_PLIST: + if (fmt == PLIST_FORMAT_BINARY) { + return property_list_service_send_binary_plist((property_list_service_client_t)service->client, plist); + } + return property_list_service_send_xml_plist((property_list_service_client_t)service->client, plist); + default: + break; + } + return -1; +} + +static int _restore_service_recv(restore_service_client_t service, plist_t *plist) +{ + if (!service) { + return -1; + } + switch (service->type) { + case SERVICE_TYPE_RESTORED: + return restored_receive((restored_client_t)service->client, plist); + case SERVICE_TYPE_PLIST: + return property_list_service_receive_plist((property_list_service_client_t)service->client, plist); + default: + break; + } + return -1; +} + +static void _restore_service_free(restore_service_client_t service) +{ + if (!service) { + return; + } + switch (service->type) { + case SERVICE_TYPE_RESTORED: + break; + case SERVICE_TYPE_PLIST: + property_list_service_client_free((property_list_service_client_t)service->client); + break; + default: + break; + } + free(service); +} + static int lastop = 0; static int restore_handle_previous_restore_log_msg(restored_client_t client, plist_t msg) @@ -686,6 +784,9 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t info("%s (%d)\n", restore_progress_string(adapted_operation), (int)operation); } switch (adapted_operation) { + case RESTORE_IMAGE: + idevicerestore_progress(client, RESTORE_STEP_UPLOAD_FS, progress / 100.0); + break; case VERIFY_RESTORE: idevicerestore_progress(client, RESTORE_STEP_VERIFY_FS, progress / 100.0); break; @@ -715,7 +816,7 @@ int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t return 0; } -int restore_handle_status_msg(restored_client_t client, plist_t msg) +int restore_handle_status_msg(struct idevicerestore_client_t* client, plist_t msg) { int result = 0; uint64_t value = 0; @@ -781,10 +882,10 @@ int restore_handle_status_msg(restored_client_t client, plist_t msg) return result; } -static int restore_handle_baseband_updater_output_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) +static int restore_handle_baseband_updater_output_data(struct idevicerestore_client_t* client, plist_t message) { int result = -1; - plist_t node = plist_dict_get_item(msg, "DataPort"); + plist_t node = plist_dict_get_item(message, "DataPort"); uint64_t u64val = 0; plist_get_uint_val(node, &u64val); uint16_t data_port = (uint16_t)u64val; @@ -855,10 +956,10 @@ static int restore_handle_baseband_updater_output_data(restored_client_t restore return result; } -static int restore_handle_bb_update_status_msg(restored_client_t client, plist_t msg) +static int restore_handle_bb_update_status_msg(struct idevicerestore_client_t* client, plist_t message) { int result = -1; - plist_t node = plist_dict_get_item(msg, "Accepted"); + plist_t node = plist_dict_get_item(message, "Accepted"); uint8_t accepted = 0; plist_get_bool_val(node, &accepted); @@ -868,14 +969,14 @@ static int restore_handle_bb_update_status_msg(restored_client_t client, plist_t } uint8_t done = 0; - node = plist_access_path(msg, 2, "Output", "done"); + node = plist_access_path(message, 2, "Output", "done"); if (node && plist_get_node_type(node) == PLIST_BOOLEAN) { plist_get_bool_val(node, &done); } if (done) { info("Updating Baseband completed.\n"); - plist_t provisioning = plist_access_path(msg, 2, "Output", "provisioning"); + plist_t provisioning = plist_access_path(message, 2, "Output", "provisioning"); if (provisioning && plist_get_node_type(provisioning) == PLIST_DICT) { char* sval = NULL; node = plist_dict_get_item(provisioning, "IMEI"); @@ -903,7 +1004,7 @@ static void restore_asr_progress_cb(double progress, void* userdata) } } -int restore_send_filesystem(struct idevicerestore_client_t* client) +int restore_send_filesystem(struct idevicerestore_client_t* client, plist_t message) { asr_client_t asr = NULL; ipsw_archive_t ipsw_dummy = NULL; @@ -936,7 +1037,11 @@ int restore_send_filesystem(struct idevicerestore_client_t* client) free(fsname); } - if (asr_open_with_timeout(client->restore->device, &asr) < 0) { + uint16_t asr_port = (uint16_t)plist_dict_get_uint(message, "DataPort"); + if (asr_port == 0) { + asr_port = ASR_DEFAULT_PORT; + } + if (asr_open_with_timeout(client->restore->device, &asr, asr_port) < 0) { ipsw_file_close(file); ipsw_close(ipsw_dummy); error("ERROR: Unable to connect to ASR\n"); @@ -944,7 +1049,9 @@ int restore_send_filesystem(struct idevicerestore_client_t* client) } info("Connected to ASR\n"); - asr_set_progress_callback(asr, restore_asr_progress_cb, (void*)client); + if (asr_port == ASR_DEFAULT_PORT) { + asr_set_progress_callback(asr, restore_asr_progress_cb, (void*)client); + } // this step sends requested chunks of data from various offsets to asr so // it can validate the filesystem before installing it @@ -977,7 +1084,7 @@ int restore_send_filesystem(struct idevicerestore_client_t* client) return 0; } -int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client) +int restore_send_recovery_os_root_ticket(struct idevicerestore_client_t* client, plist_t message) { restored_error_t restore_error; plist_t dict; @@ -1017,9 +1124,16 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi free(data); } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending RecoveryOSRootTicket now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send RootTicket (%d)\n", restore_error); return -1; @@ -1030,7 +1144,7 @@ int restore_send_recovery_os_root_ticket(restored_client_t restore, struct idevi } -int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client) +int restore_send_root_ticket(struct idevicerestore_client_t* client, plist_t message) { restored_error_t restore_error; plist_t dict; @@ -1070,9 +1184,16 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl free(data); } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending RootTicket now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send RootTicket (%d)\n", restore_error); return -1; @@ -1082,7 +1203,246 @@ int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_cl return 0; } -int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, const char* component, const char* component_name) +typedef struct { + int length; + char* content; +} query_response; + +static size_t _curl_write_callback(char* data, size_t size, size_t nmemb, query_response* response) +{ + size_t total = size * nmemb; + if (total != 0) { + response->content = realloc(response->content, response->length + total + 1); + memcpy(response->content + response->length, data, total); + response->content[response->length + total] = '\0'; + response->length += total; + } + + return total; +} + +static size_t _curl_header_callback(char* buffer, size_t size, size_t nitems, void* userdata) +{ + plist_t header_dict = (plist_t)userdata; + size_t len = nitems*size; + char* key = NULL; + char* val = NULL; + size_t i = 0; + while (i < len) { + if (buffer[i] == ':') { + key = malloc(i+1); + strncpy(key, buffer, i); + key[i] = '\0'; + i++; + while (i < len && buffer[i] == ' ' || buffer[i] == '\t') i++; + val = malloc(len-i); + strncpy(val, buffer+i, len-i); + val[len-i] = '\0'; + break; + } + i++; + } + if (key && val) { + plist_dict_set_item(header_dict, key, plist_new_string(val)); + } + free(key); + free(val); + return len; +} + +int restore_send_url_asset(struct idevicerestore_client_t* client, plist_t message) +{ + debug("DEBUG: %s\n", __func__); + plist_t arguments = plist_dict_get_item(message, "Arguments"); + if (!PLIST_IS_DICT(arguments)) { + error("ERROR: %s: Unexpected arguments\n", __func__); + debug_plist(arguments); + return -1; + } + + const char* request_method = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestMethod"), NULL); + if (!request_method) { + error("ERROR: %s: Unable to extract RequestMethod from Arguments\n", __func__); + return -1; + } + if (strcmp(request_method, "GET")) { + error("ERROR: %s: Unexpected RequestMethod '%s' in message\n", __func__, request_method); + return -1; + } + const char* request_url = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestURL"), NULL); + if (!request_url) { + error("ERROR: %s: Unable to extract RequestURL from Arguments\n", __func__); + return -1; + } + info("Requesting URLAsset from %s\n", request_url); + + char curl_error_message[CURL_ERROR_SIZE]; + CURL* handle = curl_easy_init(); + /* disable SSL verification to allow download from untrusted https locations */ + curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); + + query_response* response = malloc(sizeof(query_response)); + if (response == NULL) { + error("ERROR: %s: Unable to allocate sufficient memory\n", __func__); + return -1; + } + + response->length = 0; + response->content = malloc(1); + response->content[0] = '\0'; + + curl_easy_setopt(handle, CURLOPT_HTTPGET, 1L); + curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_message); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&_curl_write_callback); + curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, &_curl_header_callback); + plist_t response_headers = plist_new_dict(); + curl_easy_setopt(handle, CURLOPT_HEADERDATA, response_headers); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); + if (idevicerestore_debug) { + curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); + } + curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(handle, CURLOPT_URL, request_url); + curl_easy_perform(handle); + + long http_response = 0; + curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_response); + + curl_easy_cleanup(handle); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "ResponseBody", plist_new_data(response->content, response->length)); + plist_dict_set_item(dict, "ResponseBodyDone", plist_new_bool(1)); + plist_dict_set_item(dict, "ResponseHeaders", response_headers); + plist_dict_set_item(dict, "ResponseStatus", plist_new_uint(http_response)); + + free(response); + + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + + _restore_service_send(service, dict, PLIST_FORMAT_BINARY); + _restore_service_free(service); + + return 0; +} + +int restore_send_streamed_image_decryption_key(struct idevicerestore_client_t* client, plist_t message) +{ + debug("DEBUG: %s\n", __func__); + plist_t arguments = plist_dict_get_item(message, "Arguments"); + if (!PLIST_IS_DICT(arguments)) { + error("ERROR: %s: Unexpected arguments\n", __func__); + debug_plist(arguments); + return -1; + } + + const char* request_method = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestMethod"), NULL); + if (!request_method) { + error("ERROR: %s: Unable to extract RequestMethod from Arguments\n", __func__); + return -1; + } + if (strcmp(request_method, "POST")) { + error("ERROR: %s: Unexpected RequestMethod '%s' in message\n", __func__, request_method); + return -1; + } + const char* request_url = plist_get_string_ptr(plist_dict_get_item(arguments, "RequestURL"), NULL); + if (!request_url) { + error("ERROR: %s: Unable to extract RequestURL from Arguments\n", __func__); + return -1; + } + + struct curl_slist* header = NULL; + + plist_t headers = plist_dict_get_item(arguments, "RequestAdditionalHeaders"); + if (!headers) { + error("ERROR: %s: Missing 'RequestAdditionalHeaders'\n", __func__); + return -1; + } + + uint64_t request_body_size = 0; + const char* request_body = plist_get_data_ptr(plist_dict_get_item(arguments, "RequestBody"), &request_body_size); + if (!request_body) { + error("ERROR: %s: Missing 'RequestBody'\n", __func__); + return -1; + } + + info("Requesting image decryption key from %s\n", request_url); + + char curl_error_message[CURL_ERROR_SIZE]; + char header_tmp[1024]; + plist_dict_iter iter = NULL; + plist_dict_new_iter(headers, &iter); + plist_t node = NULL; + do { + char *key = NULL; + plist_dict_next_item(headers, iter, &key, &node); + if (!node) break; + snprintf(header_tmp, sizeof(header_tmp), "%s: %s", key, plist_get_string_ptr(node, NULL)); + curl_slist_append(header, header_tmp); + } while (node); + plist_mem_free(iter); + + CURL* handle = curl_easy_init(); + /* disable SSL verification to allow download from untrusted https locations */ + curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); + + query_response* response = malloc(sizeof(query_response)); + if (response == NULL) { + error("ERROR: %s: Unable to allocate sufficient memory\n", __func__); + return -1; + } + + response->length = 0; + response->content = malloc(1); + response->content[0] = '\0'; + + curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curl_error_message); + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)&_curl_write_callback); + curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, &_curl_header_callback); + plist_t response_headers = plist_new_dict(); + curl_easy_setopt(handle, CURLOPT_HEADERDATA, response_headers); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); + curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header); + curl_easy_setopt(handle, CURLOPT_POSTFIELDS, request_body); + curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, request_body_size); + if (idevicerestore_debug) { + curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); + } + curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(handle, CURLOPT_URL, request_url); + curl_easy_perform(handle); + curl_slist_free_all(header); + + long http_response = 0; + curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &http_response); + + curl_easy_cleanup(handle); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "ResponseBody", plist_new_data(response->content, response->length)); + plist_dict_set_item(dict, "ResponseBodyDone", plist_new_bool(1)); + plist_dict_set_item(dict, "ResponseHeaders", response_headers); + plist_dict_set_item(dict, "ResponseStatus", plist_new_uint(http_response)); + + free(response); + + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + + _restore_service_send(service, dict, PLIST_FORMAT_BINARY); + _restore_service_free(service); + + return 0; +} + +int restore_send_component(struct idevicerestore_client_t* client, plist_t message, const char* component, const char* component_name) { unsigned int size = 0; unsigned char* data = NULL; @@ -1139,9 +1499,16 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie plist_dict_set_item(dict, compkeyname, blob); free(data); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending %s now...\n", component_name); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send component %s data\n", component_name); return -1; @@ -1151,7 +1518,7 @@ int restore_send_component(restored_client_t restore, struct idevicerestore_clie return 0; } -int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) +int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) { char* llb_path = NULL; char* llb_filename = NULL; @@ -1460,15 +1827,22 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* if (idevicerestore_debug) debug_plist(dict); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending NORData now...\n"); - if (restored_send(restore, dict) != RESTORE_E_SUCCESS) { + restored_error_t restore_error = _restore_service_send(service, dict, 0); + plist_free(dict); + _restore_service_free(service); + if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send NORData\n"); - plist_free(dict); return -1; } info("Done sending NORData\n"); - plist_free(dict); return 0; } @@ -1840,7 +2214,7 @@ static int restore_sign_bbfw(const char* bbfwtmp, plist_t bbtss, const unsigned return res; } -static int restore_send_baseband_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) +static int restore_send_baseband_data(struct idevicerestore_client_t* client, plist_t message) { int res = -1; uint64_t bb_cert_id = 0; @@ -1990,12 +2364,20 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer free(buffer); buffer = NULL; + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending BasebandData now...\n"); - if (restored_send(restore, dict) != RESTORE_E_SUCCESS) { + if (_restore_service_send(service, dict, 0) != RESTORE_E_SUCCESS) { error("ERROR: Unable to send BasebandData data\n"); goto leave; } + _restore_service_free(service); + info("Done sending BasebandData\n"); res = 0; @@ -2011,7 +2393,7 @@ static int restore_send_baseband_data(restored_client_t restore, struct idevicer return res; } -int restore_send_fdr_trust_data(restored_client_t restore) +int restore_send_fdr_trust_data(struct idevicerestore_client_t* client, plist_t message) { restored_error_t restore_error; plist_t dict; @@ -2023,9 +2405,16 @@ int restore_send_fdr_trust_data(restored_client_t restore) * and this is what iTunes seems to be doing too */ dict = plist_new_dict(); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending FDR Trust data now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: During sending FDR Trust data (%d)\n", restore_error); return -1; @@ -2036,7 +2425,7 @@ int restore_send_fdr_trust_data(restored_client_t restore) return 0; } -static int restore_send_image_data(restored_client_t restore, struct idevicerestore_client_t *client, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k) +static int restore_send_image_data(struct idevicerestore_client_t *client, plist_t message, const char *image_list_k, const char *image_type_k, const char *image_data_k) { restored_error_t restore_error; plist_t arguments; @@ -2140,6 +2529,12 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest free(iter); } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + dict = plist_new_dict(); if (want_image_list) { plist_dict_set_item(dict, image_list_k, matched_images); @@ -2158,8 +2553,9 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest } } - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { if (want_image_list) { error("ERROR: Failed to send %s image list (%d)\n", image_type_k, restore_error); @@ -2185,7 +2581,7 @@ static int restore_send_image_data(restored_client_t restore, struct idevicerest return 0; } -static plist_t restore_get_se_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) +static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { const char *comp_name = NULL; char *comp_path = NULL; @@ -2291,7 +2687,7 @@ static plist_t restore_get_se_firmware_data(restored_client_t restore, struct id return response; } -static plist_t restore_get_savage_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = NULL; char *comp_path = NULL; @@ -2387,7 +2783,7 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc return response; } -static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = NULL; char *comp_path = NULL; @@ -2476,7 +2872,7 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru return response; } -static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) +static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; @@ -2628,7 +3024,7 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct return response; } -static plist_t restore_get_veridian_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = "BMU,FirmwareMap"; char *comp_path = NULL; @@ -2729,7 +3125,7 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str return response; } -static plist_t restore_get_generic_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) +static plist_t restore_get_generic_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { plist_t request = NULL; plist_t response = NULL; @@ -2784,7 +3180,7 @@ static plist_t restore_get_generic_firmware_data(restored_client_t restore, stru return response; } -static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) { char *comp_name = "Baobab,TCON"; char *comp_path = NULL; @@ -2858,7 +3254,7 @@ 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 p_info) +static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) { char comp_name[64]; char *comp_path = NULL; @@ -3048,7 +3444,7 @@ static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct return response; } -static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) +static plist_t restore_get_cryptex1_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { plist_t parameters = NULL; plist_t request = NULL; @@ -3143,7 +3539,7 @@ static plist_t restore_get_cryptex1_firmware_data(restored_client_t restore, str return response; } -static int restore_send_firmware_updater_preflight(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) +static int restore_send_firmware_updater_preflight(struct idevicerestore_client_t* client, plist_t message) { plist_t dict = NULL; int restore_error; @@ -3153,11 +3549,18 @@ static int restore_send_firmware_updater_preflight(restored_client_t restore, st debug_plist(message); } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + dict = plist_new_dict(); info("Sending FirmwareResponsePreflight now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Couldn't send FirmwareResponsePreflight data (%d)\n", restore_error); return -1; @@ -3167,7 +3570,7 @@ static int restore_send_firmware_updater_preflight(restored_client_t restore, st return 0; } -static int restore_send_firmware_updater_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) +static int restore_send_firmware_updater_data(struct idevicerestore_client_t* client, plist_t message) { plist_t arguments; plist_t p_type, p_updater_name, p_loop_count, p_info; @@ -3229,7 +3632,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct plist_get_string_val(p_updater_name, &s_updater_name); if (strcmp(s_updater_name, "SE") == 0) { - fwdict = restore_get_se_firmware_data(restore, client, p_info, arguments); + fwdict = restore_get_se_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get SE firmware data\n", __func__); goto error_out; @@ -3239,59 +3642,59 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct plist_t p_info2 = plist_dict_get_item(p_info, "YonkersDeviceInfo"); if (p_info2 && plist_get_node_type(p_info2) == PLIST_DICT) { fwtype = "Yonkers"; - fwdict = restore_get_yonkers_firmware_data(restore, client, p_info2); + fwdict = restore_get_yonkers_firmware_data(client, p_info2); } else { - fwdict = restore_get_savage_firmware_data(restore, client, p_info); + fwdict = restore_get_savage_firmware_data(client, p_info); } if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, fwtype); goto error_out; } } else if (strcmp(s_updater_name, "Rose") == 0) { - fwdict = restore_get_rose_firmware_data(restore, client, p_info, arguments); + fwdict = restore_get_rose_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get Rose firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "T200") == 0) { - fwdict = restore_get_veridian_firmware_data(restore, client, p_info); + fwdict = restore_get_veridian_firmware_data(client, p_info); if (fwdict == NULL) { error("ERROR: %s: Couldn't get Veridian firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "AppleTCON") == 0) { - fwdict = restore_get_tcon_firmware_data(restore, client, p_info); + fwdict = restore_get_tcon_firmware_data(client, p_info); if (fwdict == NULL) { error("ERROR: %s: Couldn't get AppleTCON firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "PS190") == 0) { - fwdict = restore_get_generic_firmware_data(restore, client, p_info, arguments); + fwdict = restore_get_generic_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get PCON1 firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "AppleTypeCRetimer") == 0) { - fwdict = restore_get_timer_firmware_data(restore, client, p_info); + fwdict = restore_get_timer_firmware_data(client, p_info); if (fwdict == NULL) { error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); goto error_out; } } else if ((strcmp(s_updater_name, "Cryptex1") == 0) || (strcmp(s_updater_name, "Cryptex1LocalPolicy") == 0)) { - fwdict = restore_get_cryptex1_firmware_data(restore, client, p_info, arguments); + fwdict = restore_get_cryptex1_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else if (strcmp(s_updater_name, "Ace3") == 0) { - fwdict = restore_get_generic_firmware_data(restore, client, p_info, arguments); + fwdict = restore_get_generic_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; } } else { error("ERROR: %s: Got unknown updater name '%s', trying to discover from device generated request.\n", __func__, s_updater_name); - fwdict = restore_get_generic_firmware_data(restore, client, p_info, arguments); + fwdict = restore_get_generic_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, s_updater_name); goto error_out; @@ -3300,12 +3703,19 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct free(s_updater_name); s_updater_name = NULL; + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + dict = plist_new_dict(); plist_dict_set_item(dict, "FirmwareResponseData", fwdict); info("Sending FirmwareResponse data now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Couldn't send FirmwareResponse data (%d)\n", restore_error); goto error_out; @@ -3322,7 +3732,7 @@ static int restore_send_firmware_updater_data(restored_client_t restore, struct return -1; } -static int restore_send_receipt_manifest(restored_client_t restore, struct idevicerestore_client_t* client) +static int restore_send_receipt_manifest(struct idevicerestore_client_t* client, plist_t message) { plist_t dict; int restore_error; @@ -3338,12 +3748,19 @@ static int restore_send_receipt_manifest(restored_client_t restore, struct idevi goto error_out; } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + dict = plist_new_dict(); plist_dict_set_item(dict, "ReceiptManifest", plist_copy(manifest)); info("Sending ReceiptManifest data now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); plist_free(dict); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Couldn't send ReceiptManifest data (%d)\n", restore_error); goto error_out; @@ -3460,7 +3877,7 @@ static int restore_bootability_send_one(void *ctx, ipsw_archive_t ipsw, const ch return ret; } -static int restore_send_bootability_bundle_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message) +static int restore_send_bootability_bundle_data(struct idevicerestore_client_t* client, plist_t message) { if (idevicerestore_debug) { debug("DEBUG: %s: Got BootabilityBundle request:\n", __func__); @@ -3528,16 +3945,16 @@ plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8 plist_t unique_id_node = plist_dict_get_item(client->build_manifest, "UniqueBuildID"); if (unique_id_node) { - printf("UniqueBuildID: "); + info("UniqueBuildID: "); plist_write_to_stream(unique_id_node, stdout, PLIST_FORMAT_PRINT, PLIST_OPT_NONE); } return build_identity; } -plist_t restore_get_build_identity_from_request(struct idevicerestore_client_t* client, plist_t msg) +plist_t restore_get_build_identity_from_request(struct idevicerestore_client_t* client, plist_t message) { - plist_t args = plist_dict_get_item(msg, "Arguments"); + plist_t args = plist_dict_get_item(message, "Arguments"); return restore_get_build_identity(client, plist_dict_get_bool(args, "IsRecoveryOS")); } @@ -3617,7 +4034,7 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil struct _restore_send_file_data_ctx { struct idevicerestore_client_t* client; - restored_client_t restore; + restore_service_client_t service; int last_progress; }; @@ -3631,13 +4048,22 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi // Send FileDataDone to mark end of transfer plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1)); } - restored_error_t restore_error = restored_send(rctx->restore, dict); + restored_error_t restore_error = _restore_service_send(rctx->service, dict, 0); if (restore_error != RESTORE_E_SUCCESS) { plist_free(dict); error("ERROR: %s: Failed to send data (%d)\n", __func__, restore_error); return -1; } plist_free(dict); + + /* special handling for AEA image format */ + if (done == 0 && (memcmp(data, "AEA1", 4) == 0)) { + info("Encountered First Chunk in AEA image\n"); + plist_t message = NULL; + _restore_service_recv(rctx->service, &message); + restore_send_url_asset(rctx->client, message); + } + if (total_size > 0x1000000) { double progress = (double)done / (double)total_size; int progress_int = (int)(progress*100.0); @@ -3649,15 +4075,15 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi return 0; } -int restore_send_personalized_boot_object_v3(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) +int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* client, plist_t message) { if (idevicerestore_debug) { debug("DEBUG: %s: Got PersonalizedBootObjectV3 request:\n", __func__); - debug_plist(msg); + debug_plist(message); } char *image_name = NULL; - plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName"); + plist_t node = plist_access_path(message, 2, "Arguments", "ImageName"); if (!node || plist_get_node_type(node) != PLIST_STRING) { debug("Failed to parse arguments from PersonalizedBootObjectV3 plist\n"); return -1; @@ -3703,7 +4129,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i } } if (!path) { - plist_t build_identity = restore_get_build_identity_from_request(client, msg); + plist_t build_identity = restore_get_build_identity_from_request(client, message); if (!build_identity) { error("ERROR: Unable to find a matching build identity\n"); return -1; @@ -3735,11 +4161,17 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i } } + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending %s now (%" PRIu64 " bytes)...\n", component, (uint64_t)size); struct _restore_send_file_data_ctx rctx; rctx.client = client; - rctx.restore = restore; + rctx.service = service; rctx.last_progress = 0; int64_t i = size; @@ -3747,6 +4179,7 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i int blob_size = i > 8192 ? 8192 : i; if (_restore_send_file_data(&rctx, (data + size - i), blob_size, size-i, size) < 0) { free(data); + _restore_service_free(service); error("ERROR: Unable to send component %s data\n", component); return -1; } @@ -3756,19 +4189,21 @@ int restore_send_personalized_boot_object_v3(restored_client_t restore, struct i _restore_send_file_data(&rctx, NULL, 0, size-i, size); + _restore_service_free(service); + info("Done sending %s\n", component); return 0; } -int restore_send_source_boot_object_v4(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) +int restore_send_source_boot_object_v4(struct idevicerestore_client_t* client, plist_t message) { if (idevicerestore_debug) { debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__); - debug_plist(msg); + debug_plist(message); } char *image_name = NULL; - plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName"); + plist_t node = plist_access_path(message, 2, "Arguments", "ImageName"); if (!node || plist_get_node_type(node) != PLIST_STRING) { debug("Failed to parse arguments from SourceBootObjectV4 plist\n"); return -1; @@ -3793,7 +4228,7 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice if (strcmp(image_name, "__GlobalManifest__") == 0) { char *variant = NULL; - plist_t node = plist_access_path(msg, 2, "Arguments", "Variant"); + plist_t node = plist_access_path(message, 2, "Arguments", "Variant"); if (!node || plist_get_node_type(node) != PLIST_STRING) { debug("Failed to parse arguments from SourceBootObjectV4 plist\n"); return -1; @@ -3817,7 +4252,7 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice } } if (!path) { - plist_t build_identity = restore_get_build_identity_from_request(client, msg); + plist_t build_identity = restore_get_build_identity_from_request(client, message); if (build_identity_get_component_path(build_identity, component, &path) < 0) { error("ERROR: Unable to find %s path from build identity\n", component); return -1; @@ -3833,25 +4268,34 @@ int restore_send_source_boot_object_v4(restored_client_t restore, struct idevice uint64_t fsize = 0; ipsw_get_file_size(client->ipsw, path, &fsize); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("Sending %s now (%" PRIu64 " bytes)\n", component, fsize); struct _restore_send_file_data_ctx rctx; rctx.client = client; - rctx.restore = restore; + rctx.service = service; rctx.last_progress = 0; if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) { free(path); + _restore_service_free(service); error("ERROR: Failed to send component %s\n", component); return -1; } free(path); + _restore_service_free(service); + info("Done sending %s\n", component); return 0; } -int restore_send_restore_local_policy(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) +int restore_send_restore_local_policy(struct idevicerestore_client_t* client, plist_t message) { unsigned int size = 0; unsigned char* data = NULL; @@ -3868,7 +4312,7 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer // The Update mode does not have a specific build identity for the recovery os. plist_t build_identity = restore_get_build_identity(client, client->flags & FLAG_ERASE ? 1 : 0); - int ret = get_recovery_os_local_policy_tss_response(client, build_identity, &client->tss_localpolicy, plist_dict_get_item(msg, "Arguments")); + int ret = get_recovery_os_local_policy_tss_response(client, build_identity, &client->tss_localpolicy, plist_dict_get_item(message, "Arguments")); if (ret < 0) { error("ERROR: Unable to get recovery os local policy tss response\n"); return -1; @@ -3885,7 +4329,15 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "Ap,LocalPolicy", plist_new_data((char*)data, size)); - int restore_error = restored_send(restore, dict); + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + + int restore_error = 0; + restore_error = _restore_service_send(service, dict, 0); + _restore_service_free(service); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send component %s data\n", component); return -1; @@ -3897,19 +4349,25 @@ int restore_send_restore_local_policy(restored_client_t restore, struct idevicer return 0; } -int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_client_t* client, plist_t msg) +int restore_send_buildidentity(struct idevicerestore_client_t* client, plist_t message) { restored_error_t restore_error; plist_t dict; + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + info("About to send BuildIdentity Dict...\n"); - plist_t build_identity = restore_get_build_identity_from_request(client, msg); + plist_t build_identity = restore_get_build_identity_from_request(client, message); dict = plist_new_dict(); plist_dict_set_item(dict, "BuildIdentityDict", plist_copy(build_identity)); - plist_t node = plist_access_path(msg, 2, "Arguments", "Variant"); + plist_t node = plist_access_path(message, 2, "Arguments", "Variant"); if(node) { plist_dict_set_item(dict, "Variant", plist_copy(node)); } else { @@ -3917,7 +4375,8 @@ int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_ } info("Sending BuildIdentityDict now...\n"); - restore_error = restored_send(restore, dict); + restore_error = _restore_service_send(service, dict, 0); + _restore_service_free(service); plist_free(dict); if (restore_error != RESTORE_E_SUCCESS) { error("ERROR: Unable to send BuildIdentityDict (%d)\n", restore_error); @@ -3928,7 +4387,7 @@ int restore_send_buildidentity(restored_client_t restore, struct idevicerestore_ return 0; } -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, restored_client_t restore, plist_t message) +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, plist_t message) { plist_t node = NULL; @@ -3937,38 +4396,38 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest node = plist_dict_get_item(message, "DataType"); if (node && PLIST_STRING == plist_get_node_type(node)) { const char *type = plist_get_string_ptr(node, NULL); - +debug("%s: type = %s\n", __func__, type); // this request is sent when restored is ready to receive the filesystem if (!strcmp(type, "SystemImageData")) { - if(restore_send_filesystem(client) < 0) { + if (restore_send_filesystem(client, message) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } } else if (!strcmp(type, "BuildIdentityDict")) { - if (restore_send_buildidentity(restore, client, message) < 0) { + if (restore_send_buildidentity(client, message) < 0) { error("ERROR: Unable to send RootTicket\n"); return -1; } } else if (!strcmp(type, "PersonalizedBootObjectV3")) { - if (restore_send_personalized_boot_object_v3(restore, client, message) < 0) { + if (restore_send_personalized_boot_object_v3(client, message) < 0) { error("ERROR: Unable to send PersonalizedBootObjectV3\n"); return -1; } } else if (!strcmp(type, "SourceBootObjectV4")) { - if (restore_send_source_boot_object_v4(restore, client, message) < 0) { + if (restore_send_source_boot_object_v4(client, message) < 0) { error("ERROR: Unable to send SourceBootObjectV4\n"); return -1; } } else if (!strcmp(type, "RecoveryOSLocalPolicy")) { - if (restore_send_restore_local_policy(restore, client, message) < 0) { + if (restore_send_restore_local_policy(client, message) < 0) { error("ERROR: Unable to send RecoveryOSLocalPolicy\n"); return -1; } @@ -3976,7 +4435,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest // this request is sent when restored is ready to receive the filesystem else if (!strcmp(type, "RecoveryOSASRImage")) { - if(restore_send_filesystem(client) < 0) { + if (restore_send_filesystem(client, message) < 0) { error("ERROR: Unable to send filesystem\n"); return -2; } @@ -3984,7 +4443,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest // Send RecoveryOS RTD else if(!strcmp(type, "RecoveryOSRootTicketData")) { - if (restore_send_recovery_os_root_ticket(restore, client) < 0) { + if (restore_send_recovery_os_root_ticket(client, message) < 0) { error("ERROR: Unable to send RootTicket\n"); return -1; } @@ -3992,35 +4451,35 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest // send RootTicket (== APTicket from the TSS request) else if (!strcmp(type, "RootTicket")) { - if (restore_send_root_ticket(restore, client) < 0) { + if (restore_send_root_ticket(client, message) < 0) { error("ERROR: Unable to send RootTicket\n"); return -1; } } // send KernelCache else if (!strcmp(type, "KernelCache")) { - if (restore_send_component(restore, client, "KernelCache", NULL) < 0) { + if (restore_send_component(client, message, "KernelCache", NULL) < 0) { error("ERROR: Unable to send kernelcache\n"); return -1; } } else if (!strcmp(type, "DeviceTree")) { - if (restore_send_component(restore, client, "DeviceTree", NULL) < 0) { + if (restore_send_component(client, message, "DeviceTree", NULL) < 0) { error("ERROR: Unable to send DeviceTree\n"); return -1; } } else if (!strcmp(type, "SystemImageRootHash")) { - if (restore_send_component(restore, client, "SystemVolume", type) < 0) { + if (restore_send_component(client, message, "SystemVolume", type) < 0) { error("ERROR: Unable to send SystemImageRootHash data\n"); return -1; } } else if (!strcmp(type, "SystemImageCanonicalMetadata")) { - if (restore_send_component(restore, client, "Ap,SystemVolumeCanonicalMetadata", type) < 0) { + if (restore_send_component(client, message, "Ap,SystemVolumeCanonicalMetadata", type) < 0) { error("ERROR: Unable to send SystemImageCanonicalMetadata data\n"); return -1; } @@ -4028,7 +4487,7 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest else if (!strcmp(type, "NORData")) { if((client->flags & FLAG_EXCLUDE) == 0) { - if(restore_send_nor(restore, client, message) < 0) { + if(restore_send_nor(client, message) < 0) { error("ERROR: Unable to send NOR data\n"); return -1; } @@ -4039,75 +4498,89 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest } else if (!strcmp(type, "BasebandData")) { - if(restore_send_baseband_data(restore, client, message) < 0) { + if(restore_send_baseband_data(client, message) < 0) { error("ERROR: Unable to send baseband data\n"); return -1; } } else if (!strcmp(type, "FDRTrustData")) { - if(restore_send_fdr_trust_data(restore) < 0) { + if(restore_send_fdr_trust_data(client, message) < 0) { error("ERROR: Unable to send FDR Trust data\n"); return -1; } } else if (!strcmp(type, "FUDData")) { - if(restore_send_image_data(restore, client, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) { + if(restore_send_image_data(client, message, "FUDImageList", "IsFUDFirmware", "FUDImageData") < 0) { error("ERROR: Unable to send FUD data\n"); return -1; } } else if (!strcmp(type, "FirmwareUpdaterPreflight")) { - if(restore_send_firmware_updater_preflight(restore, client, message) < 0) { + if(restore_send_firmware_updater_preflight(client, message) < 0) { error("ERROR: Unable to send FirmwareUpdaterPreflight\n"); return -1; } } else if (!strcmp(type, "FirmwareUpdaterData")) { - if(restore_send_firmware_updater_data(restore, client, message) < 0) { + if(restore_send_firmware_updater_data(client, message) < 0) { error("ERROR: Unable to send FirmwareUpdater data\n"); return -1; } } else if (!strcmp(type, "PersonalizedData")) { - if(restore_send_image_data(restore, client, message, "ImageList", NULL, "ImageData") < 0) { + if(restore_send_image_data(client, message, "ImageList", NULL, "ImageData") < 0) { error("ERROR: Unable to send Personalized data\n"); return -1; } } else if (!strcmp(type, "EANData")) { - if(restore_send_image_data(restore, client, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) { + if(restore_send_image_data(client, message, "EANImageList", "IsEarlyAccessFirmware", "EANData") < 0) { error("ERROR: Unable to send Personalized data\n"); return -1; } } else if (!strcmp(type, "BootabilityBundle")) { - if (restore_send_bootability_bundle_data(restore, client, message) < 0) { + if (restore_send_bootability_bundle_data(client, message) < 0) { error("ERROR: Unable to send BootabilityBundle data\n"); return -1; } } else if (!strcmp(type, "ReceiptManifest")) { - if (restore_send_receipt_manifest(restore, client) < 0) { + if (restore_send_receipt_manifest(client, message) < 0) { error("ERROR: Unable to send ReceiptManifest data\n"); return -1; } } else if (!strcmp(type, "BasebandUpdaterOutputData")) { - if (restore_handle_baseband_updater_output_data(restore, client, message) < 0) { + if (restore_handle_baseband_updater_output_data(client, message) < 0) { error("ERROR: Unable to send BasebandUpdaterOutputData data\n"); return -1; } } + else if (!strcmp(type, "URLAsset")) { + if (restore_send_url_asset(client, message) < 0) { + error("ERROR: Unable to send URLAsset data\n"); + return -1; + } + } + + else if (!strcmp(type, "StreamedImageDecryptionKey")) { + if (restore_send_streamed_image_decryption_key(client, message) < 0) { + error("ERROR: Unable to send StreamedImageDecryptionKey data\n"); + return -1; + } + } + else { // Unknown DataType!! error("Unknown data request '%s' received\n", type); @@ -4118,6 +4591,70 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, rest return 0; } +struct _restore_async_args { + struct idevicerestore_client_t* client; + plist_t message; +}; + +static void* _restore_handle_async_data_request(void* args) +{ + struct _restore_async_args* async_args = (struct _restore_async_args*)args; + struct idevicerestore_client_t* client = async_args->client; + plist_t message = async_args->message; + free(async_args); + + int err = restore_handle_data_request_msg(client, message); + if (err < 0) { + client->async_err = err; + client->flags |= FLAG_QUIT; + } + + plist_free(message); + return NULL; +} + +static int restore_handle_restored_crash(struct idevicerestore_client_t* client, plist_t message) +{ + plist_t backtrace = plist_dict_get_item(message, "RestoredBacktrace"); + info("*** restored crashed, backtrace following ***"); + if (PLIST_IS_STRING(backtrace)) { + info("%s\n", plist_get_string_ptr(backtrace, NULL)); + } else if (PLIST_IS_ARRAY(backtrace)) { + uint32_t i = 0; + for (i = 0; i < plist_array_get_size(backtrace); i++) { + plist_t line = plist_array_get_item(backtrace, i); + info("\t%s\n", plist_get_string_ptr(line, NULL)); + } + } else { + debug_plist(message); + } + return 0; +} + +static int restore_handle_async_wait(struct idevicerestore_client_t* client, plist_t message) +{ + debug("AsyncWait\n"); + if (idevicerestore_debug) + debug_plist(message); + return 0; +} + +static int restore_handle_restore_attestation(struct idevicerestore_client_t* client, plist_t message) +{ + if (idevicerestore_debug) + debug_plist(message); + debug("Sending RestoreShouldAttest: false\n"); + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "RestoreShouldAttest", plist_new_bool(0)); + restored_error_t restore_error = restored_send(client->restore->client, dict); + plist_free(dict); + if (restore_error != RESTORE_E_SUCCESS) { + error("ERROR: Unable to send RestoreShouldAttest (%d)\n", restore_error); + return -1; + } + return 0; +} + // Extracted from ac2 plist_t restore_supported_data_types() { @@ -4184,6 +4721,10 @@ plist_t restore_supported_data_types() plist_dict_set_item(dict, "RestoreLocalPolicy", plist_new_bool(1)); plist_dict_set_item(dict, "AuthInstallCACert", plist_new_bool(1)); plist_dict_set_item(dict, "OverlayRootDataForKeyIndex", plist_new_bool(1)); + plist_dict_set_item(dict, "FirmwareUpdaterDataV3", plist_new_bool(1)); + plist_dict_set_item(dict, "MessageUseStreamedImageFile", plist_new_bool(1)); + plist_dict_set_item(dict, "UpdateVolumeOverlayRootDataCount", plist_new_bool(1)); + plist_dict_set_item(dict, "URLAsset", plist_new_bool(1)); return dict; } @@ -4204,6 +4745,9 @@ plist_t restore_supported_message_types() plist_dict_set_item(dict, "ReceivedFinalStatusMsg", plist_new_bool(0)); plist_dict_set_item(dict, "RestoredCrash", plist_new_bool(1)); plist_dict_set_item(dict, "StatusMsg", plist_new_bool(0)); + plist_dict_set_item(dict, "AsyncDataRequestMsg", plist_new_bool(1)); + plist_dict_set_item(dict, "AsyncWait", plist_new_bool(1)); + plist_dict_set_item(dict, "RestoreAttestation", plist_new_bool(1)); return dict; } @@ -4441,6 +4985,18 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // FIXME: does this have any effect actually? plist_dict_set_item(opts, "UpdateBaseband", plist_new_bool(0)); + // Added for iOS 18.0 beta 1 + plist_dict_set_item(opts, "HostHasFixFor99053849", plist_new_bool(1)); + plist_dict_set_item(opts, "SystemImageFormat", plist_new_string("AEAWrappedDiskImage")); + plist_dict_set_item(opts, "WaitForDeviceConnectionToFinishStateMachine", plist_new_bool(0)); + plist_t async_data_types = plist_new_dict(); + plist_dict_set_item(async_data_types, "BasebandData", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "RecoveryOSASRImage", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "StreamedImageDecryptionKey", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "SystemImageData", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "URLAsset", plist_new_bool(1)); + plist_dict_set_item(opts, "SupportedAsyncDataTypes", async_data_types); + plist_t sep = plist_access_path(build_identity, 3, "Manifest", "SEP", "Info"); if (sep) { node = plist_dict_get_item(sep, "RequiredCapacity"); @@ -4543,7 +5099,22 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // files sent to the server by the client. these data requests include // SystemImageData, RootTicket, KernelCache, NORData and BasebandData requests if (!strcmp(type, "DataRequestMsg")) { - err = restore_handle_data_request_msg(client, restore, message); + err = restore_handle_data_request_msg(client, message); + } + + // async data request message + else if (!strcmp(type, "AsyncDataRequestMsg")) { + THREAD_T t = THREAD_T_NULL; + struct _restore_async_args* args = (struct _restore_async_args*)malloc(sizeof(struct _restore_async_args)); + args->client = client; + args->message = plist_copy(message); + if (thread_new(&t, _restore_handle_async_data_request, args) < 0) { + free(args); + error("ERROR: Failed to start async data request handler thread!\n"); + err = -1; + } else { + thread_detach(t); + } } // restore logs are available if a previous restore failed @@ -4560,7 +5131,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // status messages usually indicate the current state of the restored // process or often to signal an error has been encountered else if (!strcmp(type, "StatusMsg")) { - err = restore_handle_status_msg(restore, message); + err = restore_handle_status_msg(client, message); if (restore_finished) { plist_t dict = plist_new_dict(); plist_dict_set_item(dict, "MsgType", plist_new_string("ReceivedFinalStatusMsg")); @@ -4579,7 +5150,8 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit node = plist_dict_get_item(message, "CHECKPOINT_ID"); if (!node || plist_get_node_type(node) != PLIST_INT) { debug("Failed to parse checkpoint id from checkpoint plist\n"); - return -1; + err = -1; + break; } plist_get_uint_val(node, &ckpt_id); // Get checkpoint_name @@ -4589,7 +5161,8 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit node = plist_dict_get_item(message, "CHECKPOINT_RESULT"); if (!node || plist_get_node_type(node) != PLIST_INT) { debug("Failed to parse checkpoint result from checkpoint plist\n"); - return -1; + err = -1; + break; } plist_get_int_val(node, &ckpt_res); // Get checkpoint complete @@ -4615,12 +5188,26 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // baseband update message else if (!strcmp(type, "BBUpdateStatusMsg")) { - err = restore_handle_bb_update_status_msg(restore, message); + err = restore_handle_bb_update_status_msg(client, message); } // baseband updater output data request else if (!strcmp(type, "BasebandUpdaterOutputData")) { - err = restore_handle_baseband_updater_output_data(restore, client, message); + err = restore_handle_baseband_updater_output_data(client, message); + } + + // handle restored crash, print backtrace + else if (!strcmp(type, "RestoredCrash")) { + err = restore_handle_restored_crash(client, message); + } + + // handle async wait + else if (!strcmp(type, "AsyncWait")) { + err = restore_handle_async_wait(client, message); + } + + else if (!strcmp(type, "RestoreAttestation")) { + err = restore_handle_restore_attestation(client, message); } // there might be some other message types i'm not aware of, but I think @@ -4635,6 +5222,9 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit plist_free(message); message = NULL; } + if (client->async_err != 0) { + err = client->async_err; + } #ifdef HAVE_REVERSE_PROXY reverse_proxy_client_free(rproxy); diff --git a/src/restore.h b/src/restore.h index 851b1813..763331dd 100644 --- a/src/restore.h +++ b/src/restore.h @@ -50,16 +50,16 @@ void restore_client_free(struct idevicerestore_client_t* client); int restore_is_image4_supported(struct idevicerestore_client_t* client); int restore_reboot(struct idevicerestore_client_t* client); const char* restore_progress_string(unsigned int operation); -int restore_handle_status_msg(restored_client_t client, plist_t msg); -int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t msg); -int restore_handle_data_request_msg(struct idevicerestore_client_t* client, restored_client_t restore, plist_t message); -int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t message); -int restore_send_root_ticket(restored_client_t restore, struct idevicerestore_client_t* client); -int restore_send_component(restored_client_t restore, struct idevicerestore_client_t* client, const char* component, const char* component_name); +int restore_handle_status_msg(struct idevicerestore_client_t* client, plist_t message); +int restore_handle_progress_msg(struct idevicerestore_client_t* client, plist_t message); +int restore_handle_data_request_msg(struct idevicerestore_client_t* client, plist_t message); +int restore_send_nor(struct idevicerestore_client_t* client, plist_t message); +int restore_send_root_ticket(struct idevicerestore_client_t* client, plist_t message); +int restore_send_component(struct idevicerestore_client_t* client, plist_t message, const char* component, const char* component_name); int restore_device(struct idevicerestore_client_t* client, plist_t build_identity); int restore_open_with_timeout(struct idevicerestore_client_t* client); -int restore_send_filesystem(struct idevicerestore_client_t* client); -int restore_send_fdr_trust_data(restored_client_t restore); +int restore_send_filesystem(struct idevicerestore_client_t* client, plist_t message); +int restore_send_fdr_trust_data(struct idevicerestore_client_t* client, plist_t message); #ifdef __cplusplus } From 63094e703b807441d4b84b59d2124edda04cb64f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 26 Jun 2024 16:21:42 +0200 Subject: [PATCH 091/117] restore: Always try to use DeviceGeneratedRequest data for TSS requests if present --- src/restore.c | 60 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/src/restore.c b/src/restore.c index a62886df..5c6011f5 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2687,7 +2687,7 @@ static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* clie return response; } -static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; @@ -2704,6 +2704,12 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* return NULL; } + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Savage request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2720,7 +2726,7 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* plist_dict_merge(¶meters, p_info); /* add required tags for Savage TSS request */ - tss_request_add_savage_tags(request, parameters, NULL, &comp_name); + tss_request_add_savage_tags(request, parameters, device_generated_request, &comp_name); plist_free(parameters); @@ -2783,7 +2789,7 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* return response; } -static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = NULL; char *comp_path = NULL; @@ -2799,6 +2805,12 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* return NULL; } + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Yonkers request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2817,7 +2829,7 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* plist_dict_merge(¶meters, p_info); /* add required tags for Yonkers TSS request */ - tss_request_add_yonkers_tags(request, parameters, NULL, &comp_name); + tss_request_add_yonkers_tags(request, parameters, device_generated_request, &comp_name); plist_free(parameters); @@ -3024,7 +3036,7 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl return response; } -static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = "BMU,FirmwareMap"; char *comp_path = NULL; @@ -3040,6 +3052,12 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t return NULL; } + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Veridian request */ request = tss_request_new(NULL); if (request == NULL) { @@ -3057,7 +3075,7 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t plist_dict_merge(¶meters, p_info); /* add required tags for Veridian TSS request */ - tss_request_add_veridian_tags(request, parameters, NULL); + tss_request_add_veridian_tags(request, parameters, device_generated_request); plist_free(parameters); @@ -3180,7 +3198,7 @@ static plist_t restore_get_generic_firmware_data(struct idevicerestore_client_t* return response; } -static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char *comp_name = "Baobab,TCON"; char *comp_path = NULL; @@ -3196,6 +3214,12 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl return NULL; } + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Baobab request */ request = tss_request_new(NULL); if (request == NULL) { @@ -3213,7 +3237,7 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl plist_dict_merge(¶meters, p_info); /* add required tags for Baobab TSS request */ - tss_request_add_tcon_tags(request, parameters, NULL); + tss_request_add_tcon_tags(request, parameters, device_generated_request); plist_free(parameters); @@ -3254,7 +3278,7 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl return response; } -static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* client, plist_t p_info) +static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { char comp_name[64]; char *comp_path = NULL; @@ -3275,6 +3299,12 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c return NULL; } + plist_t device_generated_request = plist_dict_get_item(arguments, "DeviceGeneratedRequest"); + if (device_generated_request && !PLIST_IS_DICT(device_generated_request)) { + error("ERROR: %s: DeviceGeneratedRequest has invalid type!\n", __func__); + return NULL; + } + /* create Timer request */ request = tss_request_new(NULL); if (request == NULL) { @@ -3345,7 +3375,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c } /* add required tags for Timer TSS request */ - tss_request_add_timer_tags(request, parameters, NULL); + tss_request_add_timer_tags(request, parameters, device_generated_request); plist_free(parameters); @@ -3642,9 +3672,9 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl plist_t p_info2 = plist_dict_get_item(p_info, "YonkersDeviceInfo"); if (p_info2 && plist_get_node_type(p_info2) == PLIST_DICT) { fwtype = "Yonkers"; - fwdict = restore_get_yonkers_firmware_data(client, p_info2); + fwdict = restore_get_yonkers_firmware_data(client, p_info2, arguments); } else { - fwdict = restore_get_savage_firmware_data(client, p_info); + fwdict = restore_get_savage_firmware_data(client, p_info, arguments); } if (fwdict == NULL) { error("ERROR: %s: Couldn't get %s firmware data\n", __func__, fwtype); @@ -3657,13 +3687,13 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl goto error_out; } } else if (strcmp(s_updater_name, "T200") == 0) { - fwdict = restore_get_veridian_firmware_data(client, p_info); + fwdict = restore_get_veridian_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get Veridian firmware data\n", __func__); goto error_out; } } else if (strcmp(s_updater_name, "AppleTCON") == 0) { - fwdict = restore_get_tcon_firmware_data(client, p_info); + fwdict = restore_get_tcon_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get AppleTCON firmware data\n", __func__); goto error_out; @@ -3675,7 +3705,7 @@ static int restore_send_firmware_updater_data(struct idevicerestore_client_t* cl goto error_out; } } else if (strcmp(s_updater_name, "AppleTypeCRetimer") == 0) { - fwdict = restore_get_timer_firmware_data(client, p_info); + fwdict = restore_get_timer_firmware_data(client, p_info, arguments); if (fwdict == NULL) { error("ERROR: %s: Couldn't get AppleTypeCRetimer firmware data\n", __func__); goto error_out; From 1d0821a79011fb5414ede7fdcb5ce4bfcee6958c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 29 Jun 2024 13:29:16 +0200 Subject: [PATCH 092/117] Remove debug printf --- src/common.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common.c b/src/common.c index 80d82560..d31c5583 100644 --- a/src/common.c +++ b/src/common.c @@ -85,7 +85,6 @@ static thread_once_t init_once = THREAD_ONCE_INIT; static void _log_init(void) { - printf("******** _log_init ********\n"); mutex_init(&log_mutex); } From 26613f928cb32fa29e31310d0e330c9c3c32085c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 1 Jul 2024 18:44:08 +0200 Subject: [PATCH 093/117] Fix heap buffer overflow in URLAsset handling --- src/restore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 5c6011f5..d3828f96 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1235,7 +1235,7 @@ static size_t _curl_header_callback(char* buffer, size_t size, size_t nitems, vo key[i] = '\0'; i++; while (i < len && buffer[i] == ' ' || buffer[i] == '\t') i++; - val = malloc(len-i); + val = malloc(len-i+1); strncpy(val, buffer+i, len-i); val[len-i] = '\0'; break; From f7e24ce6e56d67c9889744bb270ad6a98fe653f5 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 9 Jul 2024 11:45:10 +0200 Subject: [PATCH 094/117] ipsw: Fix concurrent access to ZIP file With the new AsyncDataRequestMsg we have the problem that multiple threads would access the .ipsw, however we were only using one struct zip* handle for the entire procedure, resulting in read errors when concurrent access occurs. This commit fixes it by opening the zip file for every access separately. --- src/ipsw.c | 169 ++++++++++++++++++++++++++++++++++++++++++----------- src/ipsw.h | 3 +- 2 files changed, 137 insertions(+), 35 deletions(-) diff --git a/src/ipsw.c b/src/ipsw.c index 6a747f40..3ae10661 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -300,7 +300,7 @@ int ipsw_print_info(const char* path) ipsw_archive_t ipsw_open(const char* ipsw) { int err = 0; - ipsw_archive_t archive = (ipsw_archive_t)malloc(sizeof(struct ipsw_archive)); + ipsw_archive_t archive = (ipsw_archive_t)calloc(1, sizeof(struct ipsw_archive)); if (archive == NULL) { error("ERROR: Out of memory\n"); return NULL; @@ -312,14 +312,15 @@ ipsw_archive_t ipsw_open(const char* ipsw) return NULL; } if (S_ISDIR(fst.st_mode)) { - archive->zip = NULL; + archive->zip = 0; } else { - archive->zip = zip_open(ipsw, 0, &err); - if (archive->zip == NULL) { + struct zip *zip = zip_open(ipsw, 0, &err); + if (zip == NULL) { error("ERROR: zip_open: %s: %d\n", ipsw, err); free(archive); return NULL; } + archive->zip = 1; } archive->path = strdup(ipsw); return (ipsw_archive_t)archive; @@ -329,10 +330,6 @@ void ipsw_close(ipsw_archive_t ipsw) { if (ipsw != NULL) { free(ipsw->path); - if (ipsw->zip) { - zip_unchange_all(ipsw->zip); - zip_close(ipsw->zip); - } free(ipsw); } } @@ -355,18 +352,30 @@ int ipsw_get_file_size(ipsw_archive_t ipsw, const char* infile, uint64_t* size) } if (ipsw->zip) { - int zindex = zip_name_locate(ipsw->zip, infile, 0); + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return -1; + } + int zindex = zip_name_locate(zip, infile, 0); if (zindex < 0) { error("ERROR: zip_name_locate: %s\n", infile); + zip_unchange_all(zip); + zip_close(zip); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(zip, zindex, 0, &zstat) != 0) { error("ERROR: zip_stat_index: %s\n", infile); + zip_unchange_all(zip); + zip_close(zip); return -1; } + zip_unchange_all(zip); + zip_close(zip); *size = zstat.size; } else { @@ -396,35 +405,52 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, cancel_flag = 0; if (ipsw->zip) { - int zindex = zip_name_locate(ipsw->zip, infile, 0); + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return -1; + } + + int zindex = zip_name_locate(zip, infile, 0); if (zindex < 0) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_name_locate: %s\n", infile); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(zip, zindex, 0, &zstat) != 0) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_stat_index: %s\n", infile); return -1; } char* buffer = (char*) malloc(BUFSIZE); if (buffer == NULL) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: Unable to allocate memory\n"); return -1; } - struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0); + struct zip_file* zfile = zip_fopen_index(zip, zindex, 0); if (zfile == NULL) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_fopen_index: %s\n", infile); return -1; } FILE* fd = fopen(outfile, "wb"); if (fd == NULL) { - error("ERROR: Unable to open output file: %s\n", outfile); zip_fclose(zfile); + zip_unchange_all(zip); + zip_close(zip); + error("ERROR: Unable to open output file: %s\n", outfile); return -1; } @@ -439,7 +465,10 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, size = i; count = zip_fread(zfile, buffer, size); if (count < 0) { - error("ERROR: zip_fread: %s\n", infile); + int zep = 0; + int sep = 0; + zip_file_error_get(zfile, &zep, &sep); + error("ERROR: zip_fread: %s %d %d\n", infile, zep, sep); ret = -1; break; } @@ -458,6 +487,8 @@ int ipsw_extract_to_file_with_progress(ipsw_archive_t ipsw, const char* infile, free(buffer); fclose(fd); zip_fclose(zfile); + zip_unchange_all(zip); + zip_close(zip); } else { char *filepath = build_path(ipsw->path, infile); char actual_filepath[PATH_MAX+1]; @@ -558,7 +589,15 @@ int ipsw_file_exists(ipsw_archive_t ipsw, const char* infile) } if (ipsw->zip) { - int zindex = zip_name_locate(ipsw->zip, infile, 0); + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return 0; + } + int zindex = zip_name_locate(zip, infile, 0); + zip_unchange_all(zip); + zip_close(zip); if (zindex < 0) { return 0; } @@ -584,21 +623,34 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha } if (ipsw->zip) { - int zindex = zip_name_locate(ipsw->zip, infile, 0); + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return -1; + } + + int zindex = zip_name_locate(zip, infile, 0); if (zindex < 0) { + zip_unchange_all(zip); + zip_close(zip); debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(zip, zindex, 0, &zstat) != 0) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_stat_index: %s\n", infile); return -1; } - struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0); + struct zip_file* zfile = zip_fopen_index(zip, zindex, 0); if (zfile == NULL) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_fopen_index: %s\n", infile); return -1; } @@ -608,19 +660,29 @@ int ipsw_extract_to_memory(ipsw_archive_t ipsw, const char* infile, unsigned cha if (buffer == NULL) { error("ERROR: Out of memory\n"); zip_fclose(zfile); + zip_unchange_all(zip); + zip_close(zip); return -1; } - if (zip_fread(zfile, buffer, size) != size) { - error("ERROR: zip_fread: %s\n", infile); - zip_fclose(zfile); + zip_int64_t zr = zip_fread(zfile, buffer, size); + zip_fclose(zfile); + zip_unchange_all(zip); + zip_close(zip); + if (zr < 0) { + int zep = 0; + int sep = 0; + zip_file_error_get(zfile, &zep, &sep); + error("ERROR: zip_fread: %s %d %d\n", infile, zep, sep); + free(buffer); + return -1; + } else if (zr != size) { + error("ERROR: zip_fread: %s got only %lld of %zu\n", infile, zr, size); free(buffer); return -1; } buffer[size] = '\0'; - - zip_fclose(zfile); } else { char *filepath = build_path(ipsw->path, infile); struct stat fst; @@ -691,21 +753,34 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip } if (ipsw->zip) { - int zindex = zip_name_locate(ipsw->zip, infile, 0); + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return -1; + } + + int zindex = zip_name_locate(zip, infile, 0); if (zindex < 0) { + zip_unchange_all(zip); + zip_close(zip); debug("NOTE: zip_name_locate: '%s' not found in archive.\n", infile); return -1; } struct zip_stat zstat; zip_stat_init(&zstat); - if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) { + if (zip_stat_index(zip, zindex, 0, &zstat) != 0) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_stat_index: %s\n", infile); return -1; } - struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0); + struct zip_file* zfile = zip_fopen_index(zip, zindex, 0); if (zfile == NULL) { + zip_unchange_all(zip); + zip_close(zip); error("ERROR: zip_fopen_index: %s\n", infile); return -1; } @@ -713,8 +788,10 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip total_size = zstat.size; buffer = (unsigned char*) malloc(blocksize); if (buffer == NULL) { - error("ERROR: Out of memory\n"); zip_fclose(zfile); + zip_unchange_all(zip); + zip_close(zip); + error("ERROR: Out of memory\n"); return -1; } @@ -736,6 +813,9 @@ int ipsw_extract_send(ipsw_archive_t ipsw, const char* infile, int blocksize, ip done += zr; } free(buffer); + zip_fclose(zfile); + zip_unchange_all(zip); + zip_close(zip); } else { char *filepath = build_path(ipsw->path, infile); struct stat fst; @@ -918,7 +998,14 @@ int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx) } if (ipsw->zip) { - int64_t entries = zip_get_num_entries(ipsw->zip, 0); + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return -1; + } + + int64_t entries = zip_get_num_entries(zip, 0); if (entries < 0) { error("ERROR: zip_get_num_entries failed\n"); return -1; @@ -928,7 +1015,7 @@ int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx) zip_stat_t stat; zip_stat_init(&stat); - if (zip_stat_index(ipsw->zip, index, 0, &stat) < 0) { + if (zip_stat_index(zip, index, 0, &stat) < 0) { error("ERROR: zip_stat_index failed for %s\n", stat.name); ret = -1; continue; @@ -936,7 +1023,7 @@ int ipsw_list_contents(ipsw_archive_t ipsw, ipsw_list_cb cb, void *ctx) uint8_t opsys; uint32_t attributes; - if (zip_file_get_external_attributes(ipsw->zip, index, 0, &opsys, &attributes) < 0) { + if (zip_file_get_external_attributes(zip, index, 0, &opsys, &attributes) < 0) { error("ERROR: zip_file_get_external_attributes failed for %s\n", stat.name); ret = -1; continue; @@ -1300,23 +1387,35 @@ ipsw_file_handle_t ipsw_file_open(ipsw_archive_t ipsw, const char* path) { ipsw_file_handle_t handle = (ipsw_file_handle_t)calloc(1, sizeof(struct ipsw_file_handle)); if (ipsw->zip) { + int err = 0; + struct zip *zip = zip_open(ipsw->path, 0, &err); + if (zip == NULL) { + error("ERROR: zip_open: %s: %d\n", ipsw->path, err); + return NULL; + } + zip_stat_t zst; - zip_int64_t zindex = zip_name_locate(ipsw->zip, path, 0); + zip_int64_t zindex = zip_name_locate(zip, path, 0); if (zindex < 0) { error("ERROR: zip_name_locate: %s not found\n", path); + zip_unchange_all(zip); + zip_close(zip); free(handle); return NULL; } - handle->zfile = zip_fopen_index(ipsw->zip, zindex, 0); + handle->zfile = zip_fopen_index(zip, zindex, 0); if (handle->zfile == NULL) { error("ERROR: zip_fopen_index: %s could not be opened\n", path); + zip_unchange_all(zip); + zip_close(zip); free(handle); return NULL; } zip_stat_init(&zst); - zip_stat(ipsw->zip, path, 0, &zst); + zip_stat(zip, path, 0, &zst); handle->size = zst.size; handle->seekable = (zst.comp_method == ZIP_CM_STORE); + handle->zip = zip; } else { struct stat st; char *filepath = build_path(ipsw->path, path); @@ -1338,6 +1437,8 @@ void ipsw_file_close(ipsw_file_handle_t handle) { if (handle && handle->zfile) { zip_fclose(handle->zfile); + zip_unchange_all(handle->zip); + zip_close(handle->zip); } else if (handle && handle->file) { fclose(handle->file); } diff --git a/src/ipsw.h b/src/ipsw.h index f0e11a12..8cb25612 100644 --- a/src/ipsw.h +++ b/src/ipsw.h @@ -33,7 +33,7 @@ extern "C" { #include struct ipsw_archive { - struct zip* zip; + int zip; char *path; }; typedef struct ipsw_archive* ipsw_archive_t; @@ -48,6 +48,7 @@ typedef int (*ipsw_send_cb)(void *ctx, void *data, size_t size, size_t done, siz struct ipsw_file_handle { FILE* file; + struct zip* zip; struct zip_file* zfile; uint64_t size; int seekable; From 7df9e9e43bb116ad963024f9fb1735a6b24b6806 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 18 Sep 2024 18:32:44 +0200 Subject: [PATCH 095/117] restore: Make wait for URLAsset on first chunk optional --- src/restore.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/restore.c b/src/restore.c index d3828f96..2b1ad3ea 100644 --- a/src/restore.c +++ b/src/restore.c @@ -698,16 +698,22 @@ static int _restore_service_send(restore_service_client_t service, plist_t plist return -1; } -static int _restore_service_recv(restore_service_client_t service, plist_t *plist) +static int _restore_service_recv_timeout(restore_service_client_t service, plist_t *plist, unsigned int timeout) { + struct restored_client_private { + property_list_service_client_t parent; + char *udid; + char *label; + plist_t info; + }; if (!service) { return -1; } switch (service->type) { case SERVICE_TYPE_RESTORED: - return restored_receive((restored_client_t)service->client, plist); + return property_list_service_receive_plist_with_timeout(((struct restored_client_private*)service->client)->parent, plist, timeout); case SERVICE_TYPE_PLIST: - return property_list_service_receive_plist((property_list_service_client_t)service->client, plist); + return property_list_service_receive_plist_with_timeout((property_list_service_client_t)service->client, plist, timeout); default: break; } @@ -4090,8 +4096,12 @@ static int _restore_send_file_data(struct _restore_send_file_data_ctx* rctx, voi if (done == 0 && (memcmp(data, "AEA1", 4) == 0)) { info("Encountered First Chunk in AEA image\n"); plist_t message = NULL; - _restore_service_recv(rctx->service, &message); - restore_send_url_asset(rctx->client, message); + property_list_service_error_t err = _restore_service_recv_timeout(rctx->service, &message, 3000); + if (err == PROPERTY_LIST_SERVICE_E_RECEIVE_TIMEOUT) { + info("NOTE: No URLAsset requested, assuming it is not necessary."); + } else if (err == PROPERTY_LIST_SERVICE_E_SUCCESS) { + restore_send_url_asset(rctx->client, message); + } } if (total_size > 0x1000000) { From f5d73075e00510394173299c6c328bafe8958cef Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 18 Sep 2024 18:34:03 +0200 Subject: [PATCH 096/117] restore: Make sure to error out when async data request handler can't be started When passing --ignore-errors, it would not fail when the async data request handler thread cannot be started, and might end up waiting forever for something to happen. --- src/restore.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/restore.c b/src/restore.c index 2b1ad3ea..d836470e 100644 --- a/src/restore.c +++ b/src/restore.c @@ -5152,6 +5152,9 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit free(args); error("ERROR: Failed to start async data request handler thread!\n"); err = -1; + if (client->flags & FLAG_IGNORE_ERRORS) { + client->flags &= ~FLAG_IGNORE_ERRORS; + } } else { thread_detach(t); } From 3faf2926aa03f5d9fd9e394fda9f88e22ae43a5b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 18 Sep 2024 20:56:01 +0200 Subject: [PATCH 097/117] restore: Only send FirmwareData when it has been requested --- src/restore.c | 122 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 101 insertions(+), 21 deletions(-) diff --git a/src/restore.c b/src/restore.c index d836470e..fc583c60 100644 --- a/src/restore.c +++ b/src/restore.c @@ -2587,6 +2587,28 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist return 0; } +static int _wants_firmware_data(plist_t arguments) +{ + int result = 0; + plist_t tags = plist_access_path(arguments, 2, "DeviceGeneratedTags", "ResponseTags"); + if (tags) { + plist_array_iter iter = NULL; + plist_array_new_iter(tags, &iter); + plist_t node = NULL; + do { + plist_array_next_item(tags, iter, &node); + if (node) { + const char* tag = plist_get_string_ptr(node, NULL); + if (tag && (strcmp(tag, "FirmwareData") == 0)) { + result = 1; + } + } + } while (node); + plist_mem_free(iter); + } + return result; +} + static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* client, plist_t p_info, plist_t arguments) { const char *comp_name = NULL; @@ -2634,19 +2656,6 @@ static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* clie return NULL; } - if (build_identity_get_component_path(client->restore->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; - } - /* create SE request */ request = tss_request_new(NULL); if (request == NULL) { @@ -2685,6 +2694,27 @@ static plist_t restore_get_se_firmware_data(struct idevicerestore_client_t* clie error("ERROR: No 'SE ticket' in TSS response, this might not work\n"); } + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + return response; + } + + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); + 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) { + plist_free(response); + error("ERROR: Unable to extract '%s' component\n", comp_name); + return NULL; + } + plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size)); free(component_data); component_data = NULL; @@ -2758,8 +2788,15 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* error("ERROR: No 'Savage,Ticket' in TSS response, this might not work\n"); } + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + return response; + } + /* now get actual component data */ if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); free(comp_name); return NULL; @@ -2769,6 +2806,7 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* free(comp_path); comp_path = NULL; if (ret < 0) { + plist_free(response); error("ERROR: Unable to extract '%s' component\n", comp_name); free(comp_name); return NULL; @@ -2779,6 +2817,7 @@ static plist_t restore_get_savage_firmware_data(struct idevicerestore_client_t* component_data_tmp = realloc(component_data, (size_t)component_size+16); if (!component_data_tmp) { free(component_data); + plist_free(response); return NULL; } component_data = component_data_tmp; @@ -2821,8 +2860,6 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* request = tss_request_new(NULL); if (request == NULL) { error("ERROR: Unable to create Yonkers TSS request\n"); - free(component_data); - free(comp_name); return NULL; } @@ -2851,7 +2888,7 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* plist_free(request); if (response == NULL) { error("ERROR: Unable to fetch Yonkers ticket\n"); - free(component_data); + free(comp_name); return NULL; } @@ -2861,7 +2898,15 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* error("ERROR: No 'Yonkers,Ticket' in TSS response, this might not work\n"); } + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + free(comp_name); + return response; + } + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); free(comp_name); return NULL; @@ -2872,6 +2917,7 @@ static plist_t restore_get_yonkers_firmware_data(struct idevicerestore_client_t* free(comp_path); comp_path = NULL; if (ret < 0) { + plist_free(response); error("ERROR: Unable to extract '%s' component\n", comp_name); free(comp_name); return NULL; @@ -2913,7 +2959,6 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl request = tss_request_new(NULL); if (request == NULL) { error("ERROR: Unable to create Rose TSS request\n"); - free(component_data); return NULL; } @@ -2949,7 +2994,6 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl plist_free(request); if (response == NULL) { error("ERROR: Unable to fetch Rose ticket\n"); - free(component_data); return NULL; } @@ -2959,14 +3003,15 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl error("ERROR: No 'Rap,Ticket' in TSS response, this might not work\n"); } - /* skip FirmwareData for newer versions */ - if (client->build_major >= 20) { - debug("DEBUG: Not adding FirmwareData.\n"); + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); return response; } comp_name = "Rap,RTKitOS"; if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -2974,10 +3019,12 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl free(comp_path); comp_path = NULL; if (ret < 0) { + plist_free(response); error("ERROR: Unable to extract '%s' component\n", comp_name); return NULL; } if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) { + plist_free(response); free(component_data); error("ERROR: Failed to parse '%s' component data.\n", comp_name); return NULL; @@ -2993,6 +3040,7 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl if (build_identity_has_component(client->restore->build_identity, comp_name)) { if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -3001,6 +3049,7 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl comp_path = NULL; if (ret < 0) { ftab_free(ftab); + plist_free(response); error("ERROR: Unable to extract '%s' component\n", comp_name); return NULL; } @@ -3009,6 +3058,7 @@ static plist_t restore_get_rose_firmware_data(struct idevicerestore_client_t* cl if (ftab_parse(component_data, component_size, &rftab, &ftag) != 0) { free(component_data); ftab_free(ftab); + plist_free(response); error("ERROR: Failed to parse '%s' component data.\n", comp_name); return NULL; } @@ -3100,7 +3150,14 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t error("ERROR: No 'BMU,Ticket' in TSS response, this might not work\n"); } + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + return response; + } + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -3110,6 +3167,7 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t free(comp_path); comp_path = NULL; if (ret < 0) { + plist_free(response); error("ERROR: Unable to extract '%s' component\n", comp_name); return NULL; } @@ -3125,6 +3183,7 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t component_size = 0; if (!fw_map) { + plist_free(response); error("ERROR: Unable to parse '%s' component data as plist\n", comp_name); return NULL; } @@ -3132,6 +3191,7 @@ static plist_t restore_get_veridian_firmware_data(struct idevicerestore_client_t plist_t fw_map_digest = plist_access_path(client->restore->build_identity, 3, "Manifest", comp_name, "Digest"); if (!fw_map_digest) { plist_free(fw_map); + plist_free(response); error("ERROR: Unable to get Digest for '%s' component\n", comp_name); return NULL; } @@ -3262,8 +3322,15 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl error("ERROR: No 'Baobab,Ticket' in TSS response, this might not work\n"); } + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + return response; + } + if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { error("ERROR: Unable to get path for '%s' component\n", comp_name); + plist_free(response); return NULL; } @@ -3273,6 +3340,7 @@ static plist_t restore_get_tcon_firmware_data(struct idevicerestore_client_t* cl comp_path = NULL; if (ret < 0) { error("ERROR: Unable to extract '%s' component\n", comp_name); + plist_free(response); return NULL; } @@ -3399,9 +3467,16 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c error("ERROR: No '%s' in TSS response, this might not work\n", ticket_name); } + /* don't add FirmwareData if not requested via ResponseTags */ + if (!_wants_firmware_data(arguments)) { + debug("DEBUG: Not adding FirmwareData as it was not requested\n"); + return response; + } + sprintf(comp_name, "Timer,RTKitOS,%u", tag); if (build_identity_has_component(client->restore->build_identity, comp_name)) { if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -3410,10 +3485,12 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c comp_path = NULL; if (ret < 0) { error("ERROR: Unable to extract '%s' component\n", comp_name); + plist_free(response); return NULL; } if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) { free(component_data); + plist_free(response); error("ERROR: Failed to parse '%s' component data.\n", comp_name); return NULL; } @@ -3431,6 +3508,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c if (build_identity_has_component(client->restore->build_identity, comp_name)) { if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); + plist_free(response); error("ERROR: Unable to get path for '%s' component\n", comp_name); return NULL; } @@ -3439,6 +3517,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c comp_path = NULL; if (ret < 0) { ftab_free(ftab); + plist_free(response); error("ERROR: Unable to extract '%s' component\n", comp_name); return NULL; } @@ -3447,6 +3526,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c if (ftab_parse(component_data, component_size, &rftab, &ftag) != 0) { free(component_data); ftab_free(ftab); + plist_free(response); error("ERROR: Failed to parse '%s' component data.\n", comp_name); return NULL; } From 1c4e53e673a8f25033e4ad55e7c59af9308a7d7d Mon Sep 17 00:00:00 2001 From: tihmstar Date: Tue, 17 Sep 2024 11:01:25 +0200 Subject: [PATCH 098/117] restore: Fix incorrect fallback case When the updated behavior is not triggered, the legacy behavior must be correctly executed. Thus, always correctly fall back to old behavior instead of aborting here. For example message can be NULL when restoring iOS 1.0 (in my fork). --- src/restore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/restore.c b/src/restore.c index fc583c60..92e87ebd 100644 --- a/src/restore.c +++ b/src/restore.c @@ -650,9 +650,9 @@ typedef struct restore_service_client { static void* _restore_get_service_client_for_data_request(struct idevicerestore_client_t *client, plist_t message) { - if (!client || !client->restore || !client->restore->client || !PLIST_IS_DICT(message)) return NULL; + if (!client || !client->restore || !client->restore->client) return NULL; restore_service_client_t service = (restore_service_client_t)malloc(sizeof(struct restore_service_client)); - if (!plist_dict_get_item(message, "DataPort")) { + if (!PLIST_IS_DICT(message) || !plist_dict_get_item(message, "DataPort")) { service->client = client->restore->client; service->type = SERVICE_TYPE_RESTORED; return service; From 90c2cf1e646fcb2c0d4325ed4ce7ce252dd28a2c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 18 Sep 2024 23:22:23 +0200 Subject: [PATCH 099/117] common: Try to improve terminal output with fflush() --- src/common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/common.c b/src/common.c index d31c5583..c7be4f66 100644 --- a/src/common.c +++ b/src/common.c @@ -97,6 +97,7 @@ void info(const char* format, ...) va_start(vargs, format); vfprintf((info_stream) ? info_stream : stdout, format, vargs); va_end(vargs); + fflush(info_stream?info_stream:stdout); mutex_unlock(&log_mutex); } @@ -113,6 +114,7 @@ void error(const char* format, ...) vfprintf((error_stream) ? error_stream : stderr, format, vargs2); } va_end(vargs2); + fflush(error_stream?error_stream:stderr); mutex_unlock(&log_mutex); } @@ -128,6 +130,7 @@ void debug(const char* format, ...) va_start(vargs, format); vfprintf((debug_stream) ? debug_stream : stderr, format, vargs); va_end(vargs); + fflush(debug_stream?debug_stream:stderr); mutex_unlock(&log_mutex); } From 9764c08e4f0ca6ca0d7ebdbd9df3841c3bb691e6 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 18 Sep 2024 23:30:02 +0200 Subject: [PATCH 100/117] Only print libimobiledevice debug info for debug level > 2 --- src/idevicerestore.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 8de9186d..ae48deae 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -350,9 +350,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (client->debug_level > 0) { idevicerestore_debug = 1; if (client->debug_level > 1) { - idevice_set_debug_level(1); irecv_set_debug_level(1); } + if (client->debug_level > 2) { + idevice_set_debug_level(1); + } tss_set_debug_level(client->debug_level); } From dab6a34ef1e38a781952f53aa9746a50202f31b3 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 18 Sep 2024 23:44:48 +0200 Subject: [PATCH 101/117] Print libtatsu version alongside idevicerestore version --- src/idevicerestore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index ae48deae..3042ce34 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1837,7 +1837,7 @@ int main(int argc, char* argv[]) { break; case 'v': - info("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); + info("%s %s (libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, libtatsu_version()); return EXIT_SUCCESS; case 'T': { @@ -1895,7 +1895,7 @@ int main(int argc, char* argv[]) { return EXIT_FAILURE; } - info("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); + info("%s %s (libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, libtatsu_version()); if (ipsw) { // verify if ipsw file exists From 17c65b2dfd11b144cf3335b47c203b711fa61911 Mon Sep 17 00:00:00 2001 From: Florian Brandstetter Date: Thu, 19 Sep 2024 00:05:04 +0200 Subject: [PATCH 102/117] restore: Add SupportedAsyncDataTypes for both iOS and macOS --- src/restore.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/restore.c b/src/restore.c index 92e87ebd..47f11d11 100644 --- a/src/restore.c +++ b/src/restore.c @@ -5109,13 +5109,6 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit plist_dict_set_item(opts, "HostHasFixFor99053849", plist_new_bool(1)); plist_dict_set_item(opts, "SystemImageFormat", plist_new_string("AEAWrappedDiskImage")); plist_dict_set_item(opts, "WaitForDeviceConnectionToFinishStateMachine", plist_new_bool(0)); - plist_t async_data_types = plist_new_dict(); - plist_dict_set_item(async_data_types, "BasebandData", plist_new_bool(0)); - plist_dict_set_item(async_data_types, "RecoveryOSASRImage", plist_new_bool(0)); - plist_dict_set_item(async_data_types, "StreamedImageDecryptionKey", plist_new_bool(0)); - plist_dict_set_item(async_data_types, "SystemImageData", plist_new_bool(0)); - plist_dict_set_item(async_data_types, "URLAsset", plist_new_bool(1)); - plist_dict_set_item(opts, "SupportedAsyncDataTypes", async_data_types); plist_t sep = plist_access_path(build_identity, 3, "Manifest", "SEP", "Info"); if (sep) { @@ -5135,6 +5128,15 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit plist_dict_set_item(opts, "PersonalizedDuringPreflight", plist_new_bool(1)); } + // Added for iOS 18.0 and macOS 15.0 + plist_t async_data_types = plist_new_dict(); + plist_dict_set_item(async_data_types, "BasebandData", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "RecoveryOSASRImage", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "StreamedImageDecryptionKey", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "SystemImageData", plist_new_bool(0)); + plist_dict_set_item(async_data_types, "URLAsset", plist_new_bool(1)); + plist_dict_set_item(opts, "SupportedAsyncDataTypes", async_data_types); + plist_dict_set_item(opts, "RootToInstall", plist_new_bool(0)); char* guid = generate_guid(); if (guid) { From ad46e149702ece0af81932cc48f8603362102b96 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 19 Sep 2024 00:33:56 +0200 Subject: [PATCH 103/117] Replace sprintf with snprintf --- src/idevicerestore.c | 19 ++++++++++--------- src/img4.c | 2 +- src/ipsw.c | 12 ++++++------ src/restore.c | 25 +++++++++++++------------ 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 3042ce34..461e057b 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -393,7 +393,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } char wtfname[256]; - sprintf(wtfname, "Firmware/dfu/WTF.s5l%04xxall.RELEASE.dfu", cpid); + snprintf(wtfname, sizeof(wtfname), "Firmware/dfu/WTF.s5l%04xxall.RELEASE.dfu", cpid); unsigned char* wtftmp = NULL; unsigned int wtfsize = 0; @@ -876,7 +876,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) x++; } - sprintf(p_all_flash, "Firmware/all_flash/all_flash.%s.%s", lcmodel, "production"); + snprintf(p_all_flash, sizeof(p_all_flash), "Firmware/all_flash/all_flash.%s.%s", lcmodel, "production"); strcpy(tmpstr, p_all_flash); strcat(tmpstr, "/manifest"); @@ -926,7 +926,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } // add iBSS - sprintf(tmpstr, "Firmware/dfu/iBSS.%s.%s.dfu", lcmodel, "RELEASE"); + snprintf(tmpstr, sizeof(tmpstr), "Firmware/dfu/iBSS.%s.%s.dfu", lcmodel, "RELEASE"); inf = plist_new_dict(); plist_dict_set_item(inf, "Path", plist_new_string(tmpstr)); comp = plist_new_dict(); @@ -934,7 +934,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_dict_set_item(manifest, "iBSS", comp); // add iBEC - sprintf(tmpstr, "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE"); + snprintf(tmpstr, sizeof(tmpstr), "Firmware/dfu/iBEC.%s.%s.dfu", lcmodel, "RELEASE"); inf = plist_new_dict(); plist_dict_set_item(inf, "Path", plist_new_string(tmpstr)); comp = plist_new_dict(); @@ -1300,7 +1300,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) strcpy(zfn, "shsh"); } mkdir_with_parents(zfn, 0755); - sprintf(zfn+strlen(zfn), "/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version); + snprintf(&zfn[0]+strlen(zfn), sizeof(zfn)-strlen(zfn), "/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version); struct stat fst; if (stat(zfn, &fst) != 0) { gzFile zf = gzopen(zfn, "wb"); @@ -1755,8 +1755,9 @@ int main(int argc, char* argv[]) { if (!p || *(p+1) == '\0') { // no path component, add default path const char default_path[] = "/TSS/controller?action=2"; - char* newurl = malloc(strlen(optarg)+sizeof(default_path)); - sprintf(newurl, "%s%s", optarg, (p) ? default_path+1 : default_path); + size_t usize = strlen(optarg)+sizeof(default_path); + char* newurl = malloc(usize); + snprintf(newurl, usize, "%s%s", optarg, (p) ? default_path+1 : default_path); client->tss_url = newurl; } else { client->tss_url = strdup(optarg); @@ -2202,9 +2203,9 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident char zfn[1024]; if (client->version) { if (client->cache_dir) { - sprintf(zfn, "%s/shsh/%" PRIu64 "-%s-%s.shsh", client->cache_dir, client->ecid, client->device->product_type, client->version); + snprintf(zfn, sizeof(zfn), "%s/shsh/%" PRIu64 "-%s-%s.shsh", client->cache_dir, client->ecid, client->device->product_type, client->version); } else { - sprintf(zfn, "shsh/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version); + snprintf(zfn, sizeof(zfn), "shsh/%" PRIu64 "-%s-%s.shsh", client->ecid, client->device->product_type, client->version); } struct stat fst; if (stat(zfn, &fst) == 0) { diff --git a/src/img4.c b/src/img4.c index cfd3c934..dc21e567 100644 --- a/src/img4.c +++ b/src/img4.c @@ -448,7 +448,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo unsigned char *additional_data = NULL; unsigned int additional_size = 0; char *tbm_key = malloc(strlen(component_name) + 5); - sprintf(tbm_key, "%s-TBM", component_name); + snprintf(tbm_key, strlen(component_name)+5, "%s-TBM", component_name); plist_t tbm_dict = plist_dict_get_item(tss_response, tbm_key); free(tbm_key); if (tbm_dict) { diff --git a/src/ipsw.c b/src/ipsw.c index 3ae10661..da7528d0 100644 --- a/src/ipsw.c +++ b/src/ipsw.c @@ -76,13 +76,13 @@ int ipsw_print_info(const char* path) char thepath[PATH_MAX]; if (S_ISDIR(fst.st_mode)) { - sprintf(thepath, "%s/BuildManifest.plist", path); + snprintf(thepath, sizeof(thepath), "%s/BuildManifest.plist", path); if (stat(thepath, &fst) != 0) { error("ERROR: '%s': %s\n", thepath, strerror(errno)); return -1; } } else { - sprintf(thepath, "%s", path); + snprintf(thepath, sizeof(thepath), "%s", path); } FILE* f = fopen(thepath, "r"); @@ -1169,7 +1169,7 @@ int ipsw_get_latest_fw(plist_t version_data, const char* product, char** fwurl, } char majstr[32]; // should be enough for a uint64_t value - sprintf(majstr, "%"PRIu64, (uint64_t)major); + snprintf(majstr, sizeof(majstr), "%"PRIu64, (uint64_t)major); n1 = plist_access_path(version_data, 7, "MobileDeviceSoftwareVersionsByVersion", majstr, "MobileDeviceSoftwareVersions", product, "Unknown", "Universal", "Restore"); if (!n1) { error("%s: ERROR: Can't get Unknown/Universal/Restore node?!\n", __func__); @@ -1277,13 +1277,13 @@ int ipsw_download_fw(const char *fwurl, unsigned char* isha1, const char* todir, char fwlfn[PATH_MAX - 5]; if (todir) { - sprintf(fwlfn, "%s/%s", todir, fwfn); + snprintf(fwlfn, sizeof(fwlfn), "%s/%s", todir, fwfn); } else { - sprintf(fwlfn, "%s", fwfn); + snprintf(fwlfn, sizeof(fwlfn), "%s", fwfn); } char fwlock[PATH_MAX]; - sprintf(fwlock, "%s.lock", fwlfn); + snprintf(fwlock, sizeof(fwlock), "%s.lock", fwlfn); lock_info_t lockinfo; diff --git a/src/restore.c b/src/restore.c index 47f11d11..6fdf755e 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1501,7 +1501,7 @@ int restore_send_component(struct idevicerestore_client_t* client, plist_t messa dict = plist_new_dict(); blob = plist_new_data((char*)data, size); char compkeyname[256]; - sprintf(compkeyname, "%sFile", component_name); + snprintf(compkeyname, sizeof(compkeyname), "%sFile", component_name); plist_dict_set_item(dict, compkeyname, blob); free(data); @@ -3418,25 +3418,25 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c plist_dict_set_item(parameters, "TicketName", plist_copy(node)); } - sprintf(key, "Timer,ChipID,%u", tag); + snprintf(key, sizeof(key), "Timer,ChipID,%u", tag); plist_dict_copy_uint(parameters, hwid, key, "ChipID"); - sprintf(key, "Timer,BoardID,%u", tag); + snprintf(key, sizeof(key), "Timer,BoardID,%u", tag); plist_dict_copy_uint(parameters, hwid, key, "BoardID"); - sprintf(key, "Timer,ECID,%u", tag); + snprintf(key, sizeof(key), "Timer,ECID,%u", tag); plist_dict_copy_uint(parameters, hwid, key, "ECID"); - sprintf(key, "Timer,Nonce,%u", tag); + snprintf(key, sizeof(key), "Timer,Nonce,%u", tag); plist_dict_copy_data(parameters, hwid, key, "Nonce"); - sprintf(key, "Timer,SecurityMode,%u", tag); + snprintf(key, sizeof(key), "Timer,SecurityMode,%u", tag); plist_dict_copy_bool(parameters, hwid, key, "SecurityMode"); - sprintf(key, "Timer,SecurityDomain,%u", tag); + snprintf(key, sizeof(key), "Timer,SecurityDomain,%u", tag); plist_dict_copy_uint(parameters, hwid, key, "SecurityDomain"); - sprintf(key, "Timer,ProductionMode,%u", tag); + snprintf(key, sizeof(key), "Timer,ProductionMode,%u", tag); plist_dict_copy_uint(parameters, hwid, key, "ProductionStatus"); } plist_t ap_info = plist_dict_get_item(p_info, "APInfo"); @@ -3473,7 +3473,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c return response; } - sprintf(comp_name, "Timer,RTKitOS,%u", tag); + snprintf(comp_name, sizeof(comp_name), "Timer,RTKitOS,%u", tag); if (build_identity_has_component(client->restore->build_identity, comp_name)) { if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { plist_free(response); @@ -3504,7 +3504,7 @@ static plist_t restore_get_timer_firmware_data(struct idevicerestore_client_t* c info("NOTE: Build identity does not have a '%s' component.\n", comp_name); } - sprintf(comp_name, "Timer,RestoreRTKitOS,%u", tag); + snprintf(comp_name, sizeof(comp_name), "Timer,RestoreRTKitOS,%u", tag); if (build_identity_has_component(client->restore->build_identity, comp_name)) { if (build_identity_get_component_path(client->restore->build_identity, comp_name, &comp_path) < 0) { ftab_free(ftab); @@ -4121,8 +4121,9 @@ static char* extract_global_manifest_path(plist_t build_identity, char *variant) } // The path of the global manifest is hardcoded. There's no pointer to in the build manifest. - char *ticket_path = malloc((42+strlen(macos_variant)+strlen(device_class)+1)*sizeof(char)); - sprintf(ticket_path, "Firmware/Manifests/restore/%s/apticket.%s.im4m", macos_variant, device_class); + size_t psize = 42+strlen(macos_variant)+strlen(device_class)+1; + char *ticket_path = malloc(psize); + snprintf(ticket_path, psize, "Firmware/Manifests/restore/%s/apticket.%s.im4m", macos_variant, device_class); free(device_class); free(macos_variant); From a31eb2bf5fb2b5df1468e2ec4d31bcdc584af7d1 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 19 Sep 2024 16:13:36 +0200 Subject: [PATCH 104/117] Also print libirecovery version --- src/idevicerestore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 461e057b..36099d1b 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1838,7 +1838,7 @@ int main(int argc, char* argv[]) { break; case 'v': - info("%s %s (libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, libtatsu_version()); + info("%s %s (libirecovery %s, libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, irecv_version(), libtatsu_version()); return EXIT_SUCCESS; case 'T': { @@ -1896,7 +1896,7 @@ int main(int argc, char* argv[]) { return EXIT_FAILURE; } - info("%s %s (libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, libtatsu_version()); + info("%s %s (libirecovery %s, libtatsu %s)\n", PACKAGE_NAME, PACKAGE_VERSION, irecv_version(), libtatsu_version()); if (ipsw) { // verify if ipsw file exists From 4145e9584980f2c2d994a1b543478b38156be5e7 Mon Sep 17 00:00:00 2001 From: Florian Brandstetter Date: Sat, 21 Sep 2024 00:13:37 +0200 Subject: [PATCH 105/117] asr: Add support for second Initiate request First observed in iBridgeOS 9.0. The first Initiate ASR packet (checksum_chunks = false) requests 64 bytes of the IPSW at offset 0, after which another Initiate follows requesting a switch to (checksum_chunks = true) and additional OOBData. --- src/asr.c | 59 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/src/asr.c b/src/asr.c index b150e852..8463f0d6 100644 --- a/src/asr.c +++ b/src/asr.c @@ -202,23 +202,12 @@ void asr_free(asr_client_t asr) } } -int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) -{ - uint64_t length = 0; - char* command = NULL; - plist_t node = NULL; - plist_t packet = NULL; - plist_t packet_info = NULL; - plist_t payload_info = NULL; - int attempts = 0; - - length = ipsw_file_size(file); - - payload_info = plist_new_dict(); +int asr_send_validation_packet_info(asr_client_t asr, uint64_t ipsw_size) { + plist_t payload_info = plist_new_dict(); plist_dict_set_item(payload_info, "Port", plist_new_uint(1)); - plist_dict_set_item(payload_info, "Size", plist_new_uint(length)); + plist_dict_set_item(payload_info, "Size", plist_new_uint(ipsw_size)); - packet_info = plist_new_dict(); + plist_t packet_info = plist_new_dict(); if (asr->checksum_chunks) { plist_dict_set_item(packet_info, "Checksum Chunk Size", plist_new_uint(ASR_CHECKSUM_CHUNK_SIZE)); } @@ -230,11 +219,30 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) plist_dict_set_item(packet_info, "Version", plist_new_uint(ASR_VERSION)); if (asr_send(asr, packet_info)) { - error("ERROR: Unable to sent packet information to ASR\n"); plist_free(packet_info); return -1; } plist_free(packet_info); + plist_free(payload_info); + + return 0; +} + +int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) +{ + uint64_t length = 0; + char* command = NULL; + plist_t node = NULL; + plist_t packet = NULL; + int attempts = 0; + + length = ipsw_file_size(file); + + // Expected by device after every initiate + if (asr_send_validation_packet_info(asr, length) < 0) { + error("ERROR: Unable to send validation packet info to ASR\n"); + return -1; + } while (1) { if (asr_receive(asr, &packet) < 0) { @@ -260,6 +268,25 @@ int asr_perform_validation(asr_client_t asr, ipsw_file_handle_t file) } plist_get_string_val(node, &command); + // Added for iBridgeOS 9.0 - second initiate request to change to checksum chunks + if (!strcmp(command, "Initiate")) { + // This might switch on the second Initiate + node = plist_dict_get_item(packet, "Checksum Chunks"); + if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) { + plist_get_bool_val(node, &(asr->checksum_chunks)); + } + plist_free(packet); + + // Expected by device after every Initiate + if (asr_send_validation_packet_info(asr, length) < 0) { + error("ERROR: Unable to send validation packet info to ASR\n"); + return -1; + } + + // A OOBData request should follow + continue; + } + if (!strcmp(command, "OOBData")) { int ret = asr_handle_oob_data_request(asr, packet, file); plist_free(packet); From d2e1c4f2ab81c419d2cbb8d921fa385a0bf0433b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 21 Sep 2024 03:14:15 +0200 Subject: [PATCH 106/117] asr: Fix memory corruption due to double free --- src/asr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/asr.c b/src/asr.c index 8463f0d6..15396c4a 100644 --- a/src/asr.c +++ b/src/asr.c @@ -202,7 +202,8 @@ void asr_free(asr_client_t asr) } } -int asr_send_validation_packet_info(asr_client_t asr, uint64_t ipsw_size) { +int asr_send_validation_packet_info(asr_client_t asr, uint64_t ipsw_size) +{ plist_t payload_info = plist_new_dict(); plist_dict_set_item(payload_info, "Port", plist_new_uint(1)); plist_dict_set_item(payload_info, "Size", plist_new_uint(ipsw_size)); @@ -223,7 +224,6 @@ int asr_send_validation_packet_info(asr_client_t asr, uint64_t ipsw_size) { return -1; } plist_free(packet_info); - plist_free(payload_info); return 0; } From 48350d676e9d817c8c8f1af2cd1e0006e1ad9c3b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 21 Sep 2024 03:15:23 +0200 Subject: [PATCH 107/117] Initial support for iPhone 16 restore --- src/idevicerestore.c | 10 ++++++++++ src/img4.c | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 36099d1b..2dd7eb88 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1258,6 +1258,16 @@ int idevicerestore_start(struct idevicerestore_client_t* client) error("ERROR: Unable to get SHSH blobs for this device (recovery OS Root Ticket)\n"); return -1; } + } else { + plist_t recovery_variant = plist_access_path(build_identity, 2, "Info", "RecoveryVariant"); + if (recovery_variant) { + const char* recovery_variant_str = plist_get_string_ptr(recovery_variant, NULL); + plist_t recovery_build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, recovery_variant_str, 1); + if (get_tss_response(client, recovery_build_identity, &client->tss_recoveryos_root_ticket) < 0) { + error("ERROR: Unable to get SHSH blobs for this device (%s)\n", recovery_variant_str); + return -1; + } + } } } diff --git a/src/img4.c b/src/img4.c index dc21e567..c010ce4f 100644 --- a/src/img4.c +++ b/src/img4.c @@ -441,6 +441,14 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo memcpy((void*)tag, "rcio", 4); } else if (strcmp(component_name, "Ap,DCP2") == 0) { memcpy((void*)tag, "dcp2", 4); + } else if (strcmp(component_name, "Ap,RestoreSecureM3Firmware") == 0) { + memcpy((void*)tag, "rsm3", 4); + } else if (strcmp(component_name, "Ap,RestoreSecurePageTableMonitor") == 0) { + memcpy((void*)tag, "rspt", 4); + } else if (strcmp(component_name, "Ap,RestoreTrustedExecutionMonitor") == 0) { + memcpy((void*)tag, "rtrx", 4); + } else if (strcmp(component_name, "Ap,RestorecL4") == 0) { + memcpy((void*)tag, "rxcl", 4); } } From be6751c2cb7d63cee43a11cf93ee4a23cca699cb Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 25 Sep 2024 02:18:07 +0200 Subject: [PATCH 108/117] ace3: Fix Ace3Binary generation for newer devices --- src/ace3.c | 48 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/src/ace3.c b/src/ace3.c index b96e6b4f..a482f6f3 100644 --- a/src/ace3.c +++ b/src/ace3.c @@ -50,11 +50,39 @@ static uint32_t crc_buffer(const unsigned char* buffer, unsigned int bufsize, un return result; } +static int uarp_version_convert(uint32_t* version_data, uint32_t* version_out) +{ + if (version_out) *version_out = 0; + if (!version_data) { + return -1; + } + uint32_t part1 = (version_data[0] < 0xE00) ? version_data[0] : version_data[0] - 0xE00; + if (part1 > 0x63) { + return 0; + } + uint32_t part2 = (version_data[0] < 0xE00) ? 0 : 0xE00; + uint32_t part3 = version_data[1]; + if (part3 > 0x3E7) { + return 0; + } + uint32_t part4 = version_data[2]; + if (part4 > 0x63) { + return 0; + } + if (version_out) { + *version_out = ((((0x147B * (unsigned int)((uint16_t)part3 >> 2)) >> 9) & 0x3FF00 | (0x10 * (((uint8_t)((uint16_t)part3 / 0xA) % 0xA) & 0xF)) | ((uint16_t)part3 % 0xA)) << 8) + | ((((uint8_t)part1 % 0xA) | (0x10 * ((uint8_t)part1 / 0xA)) | part2) << 20) + | ((uint8_t)part4 % 0xA) + | ((0xCD * (unsigned int)(uint8_t)part4) >> 7) & 0xF0; + } + return 0; +} + int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t bdid, unsigned int prev, plist_t tss, unsigned char** bin_out, size_t* bin_size) { struct ace3bin_header { uint32_t magic; // 0xACE00003 - uint32_t unk4; // 0x00203400 + uint32_t version; // ace3 version, e.g. 0x00203400 uint32_t unk8; // 0x00002800 uint32_t header_size; // 0x00000040 uint32_t data1_size; @@ -84,10 +112,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t struct uarp_toc_entry { uint32_t this_size; // BE usually 0x28 uint32_t fourcc; // 'PT01' or similar - uint32_t index; // BE starting with 0, increment+1 for each entry - uint32_t unk_0c; // BE usually not zero - uint32_t unk_10; // BE usually 0 - uint32_t unk_14; // BE usually 0 + uint32_t version[4]; // BE values uint32_t unk_18; // BE other offset, not sure uint32_t unk_1c; // BE usually 0 uint32_t offset; // BE @@ -142,6 +167,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t uint64_t boardid = 0; plist_get_uint_val(p_boardid, &boardid); if (boardid == bdid) { + debug("DEBUG: %s: Found Board ID 0x%" PRIx64 "\n", __func__, bdid); plist_t p4cc = plist_dict_get_item(payload, "Payload 4CC"); plist_get_string_val(p4cc, &payload_4cc); plist_t matching = plist_dict_get_item(meta, "Personalization Matching Data"); @@ -163,6 +189,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t if (prev >= minrev && prev <= maxrev) { plist_t tags = plist_dict_get_item(match, "Personalization Matching Data Payload Tags"); plist_get_string_val(tags, &data_payload_4ccs); + debug("DEBUG: %s: Found matching tags %s\n", __func__, data_payload_4ccs); break; } } while (match); @@ -187,11 +214,12 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t uint32_t dl_size = 0; uint32_t data1_offset = 0; uint32_t data1_size = 0; + uint32_t data1_version = 0; uint32_t data2_offset = 0; uint32_t data2_size = 0; uint32_t toc_offset = be32toh(uarp_hdr->toc_offset); uint32_t toc_size = be32toh(uarp_hdr->toc_size); - const unsigned char* p = uarp_fw + uarp_hdr_size; + const unsigned char* p = uarp_fw + uarp_hdr_size; while (p < uarp_fw + toc_size) { struct uarp_toc_entry* entry = (struct uarp_toc_entry*)p; uint32_t te_size = be32toh(entry->this_size); @@ -199,8 +227,14 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t dl_offset = be32toh(entry->offset); dl_size = be32toh(entry->size); } else if (strncmp((char*)&(entry->fourcc), data_payload_4ccs, 4) == 0) { + uint32_t version_data[4]; + version_data[0] = be32toh(entry->version[0]); + version_data[1] = be32toh(entry->version[1]); + version_data[2] = be32toh(entry->version[2]); + version_data[3] = be32toh(entry->version[3]); data1_offset = be32toh(entry->offset); data1_size = be32toh(entry->size); + uarp_version_convert(version_data, &data1_version); } else if (strncmp((char*)&(entry->fourcc), data_payload_4ccs+5, 4) == 0) { data2_offset = be32toh(entry->offset); data2_size = be32toh(entry->size); @@ -213,7 +247,7 @@ int ace3_create_binary(const unsigned char* uarp_fw, size_t uarp_size, uint64_t *bin_out = (unsigned char*)malloc(0x40 + content_size); struct ace3bin_header* hdr = (struct ace3bin_header*)(*bin_out); hdr->magic = htole32(0xACE00003); - hdr->unk4 = htole32(0x00203400); + hdr->version = htole32(data1_version); hdr->unk8 = htole32(0x00002800); hdr->header_size = htole32(0x40); hdr->data1_size = htole32(data1_size); From 27402caabadfe0d5114a8999bdae413202f3d19c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 25 Sep 2024 02:46:07 +0200 Subject: [PATCH 109/117] Release DFU/Recovery client on disconnect and Increase timeout for port DFU -> KIS --- src/idevicerestore.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index 2dd7eb88..bf58a3e9 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -817,8 +817,9 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } return -2; } + dfu_client_free(client); debug("Waiting for device to reconnect in DFU mode...\n"); - cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 5000); + cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 20000); if (client->mode != MODE_DFU || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); if (!(client->flags & FLAG_QUIT)) { @@ -1416,6 +1417,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } return -2; } + recovery_client_free(client); debug("Waiting for device to reconnect in recovery mode...\n"); cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000); if (client->mode != MODE_RECOVERY || (client->flags & FLAG_QUIT)) { From 511261e12d23d80cc3c08290022380b8d3411f9c Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 28 Sep 2024 03:08:15 +0200 Subject: [PATCH 110/117] Be more precise about what is wrong when entering restore mode fails --- src/idevicerestore.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/idevicerestore.c b/src/idevicerestore.c index bf58a3e9..fb0b3290 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1494,7 +1494,11 @@ int idevicerestore_start(struct idevicerestore_client_t* client) if (client->mode != MODE_RESTORE || (client->flags & FLAG_QUIT)) { mutex_unlock(&client->device_event_mutex); error("ERROR: Device failed to enter restore mode.\n"); - error("Please make sure that usbmuxd is running.\n"); + if (client->mode == MODE_UNKNOWN) { + error("Make sure that usbmuxd is running.\n"); + } else if (client->mode == MODE_RECOVERY) { + error("Device reconnected in recovery mode, most likely image personalization failed.\n"); + } return -1; } mutex_unlock(&client->device_event_mutex); From f4a18ee13dd84d76dd6ebb9b21cd6bce6f37e4ec Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 11 Oct 2024 11:59:40 +0200 Subject: [PATCH 111/117] configure: Require newer libtatsu and libirecovery --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d0a052f8..9d71e956 100644 --- a/configure.ac +++ b/configure.ac @@ -15,12 +15,12 @@ if test -z $PACKAGE_VERSION; then fi # Minimum package versions -LIBIRECOVERY_VERSION=1.2.0 +LIBIRECOVERY_VERSION=1.2.1 LIBIMOBILEDEVICE_VERSION=1.3.0 LIBUSBMUXD_VERSION=2.0.2 LIBPLIST_VERSION=2.6.0 LIMD_GLUE_VERSION=1.3.0 -LIBTATSU_VERSION=1.0.3 +LIBTATSU_VERSION=1.0.4 LIBZIP_VERSION=1.0 LIBCURL_VERSION=7.0 From 151c680feb6a0775d1b979dbdfca2ac6fdfc8cad Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 15 Oct 2024 22:09:43 +0200 Subject: [PATCH 112/117] Fix iPhone 16 restore from normal mode and add support for RecoveryOS --- src/common.h | 3 + src/dfu.c | 2 +- src/idevicerestore.c | 60 +++++-- src/idevicerestore.h | 2 +- src/img4.c | 193 ++++++++++++++------- src/img4.h | 2 +- src/normal.c | 26 ++- src/normal.h | 1 + src/recovery.c | 2 +- src/restore.c | 391 ++++++++++++++++++++++++++++++++++++++++--- 10 files changed, 578 insertions(+), 104 deletions(-) diff --git a/src/common.h b/src/common.h index 8085a1a1..872d2f92 100644 --- a/src/common.h +++ b/src/common.h @@ -104,7 +104,9 @@ struct idevicerestore_client_t { int nonce_size; int image4supported; plist_t build_manifest; + plist_t firmware_preflight_info; plist_t preflight_info; + plist_t parameters; char* udid; char* srnm; ipsw_archive_t ipsw; @@ -131,6 +133,7 @@ struct idevicerestore_client_t { cond_t device_event_cond; int ignore_device_add_events; plist_t macos_variant; + plist_t recovery_variant; char* restore_variant; char* filesystem; int delete_fs; diff --git a/src/dfu.c b/src/dfu.c index 8557c292..e6b45afa 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -168,7 +168,7 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide unsigned char* data = NULL; uint32_t size = 0; - if (personalize_component(component, component_data, component_size, tss, &data, &size) < 0) { + if (personalize_component(client, component, component_data, component_size, tss, &data, &size) < 0) { error("ERROR: Unable to get personalized component: %s\n", component); free(component_data); return -1; diff --git a/src/idevicerestore.c b/src/idevicerestore.c index fb0b3290..b8bb1d06 100644 --- a/src/idevicerestore.c +++ b/src/idevicerestore.c @@ -1227,6 +1227,29 @@ int idevicerestore_start(struct idevicerestore_client_t* client) } else { free(nonce); } + if (client->mode == MODE_NORMAL) { + plist_t ap_params = normal_get_lockdown_value(client, NULL, "ApParameters"); + if (ap_params) { + if (!client->parameters) { + client->parameters = plist_new_dict(); + } + plist_dict_merge(&client->parameters, ap_params); + plist_t p_sep_nonce = plist_dict_get_item(ap_params, "SepNonce"); + uint64_t sep_nonce_size = 0; + const char* sep_nonce = plist_get_data_ptr(p_sep_nonce, &sep_nonce_size); + info("Getting SepNonce in normal mode... "); + int i = 0; + for (i = 0; i < sep_nonce_size; i++) { + info("%02x ", (unsigned char)sep_nonce[i]); + } + info("\n"); + plist_free(ap_params); + } + plist_t req_nonce_slot = plist_access_path(build_identity, 2, "Info", "RequiresNonceSlot"); + if (req_nonce_slot) { + plist_dict_set_item(client->parameters, "RequiresNonceSlot", plist_copy(req_nonce_slot)); + } + } } if (client->flags & FLAG_QUIT) { @@ -1263,8 +1286,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client) plist_t recovery_variant = plist_access_path(build_identity, 2, "Info", "RecoveryVariant"); if (recovery_variant) { const char* recovery_variant_str = plist_get_string_ptr(recovery_variant, NULL); - plist_t recovery_build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, recovery_variant_str, 1); - if (get_tss_response(client, recovery_build_identity, &client->tss_recoveryos_root_ticket) < 0) { + client->recovery_variant = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, recovery_variant_str, 1); + if (!client->recovery_variant) { + error("ERROR: Variant '%s' not found in BuildManifest\n", recovery_variant_str); + return -1; + } + if (get_tss_response(client, client->recovery_variant, &client->tss_recoveryos_root_ticket) < 0) { error("ERROR: Unable to get SHSH blobs for this device (%s)\n", recovery_variant_str); return -1; } @@ -1614,6 +1641,9 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client) if (client->build_manifest) { plist_free(client->build_manifest); } + if (client->firmware_preflight_info) { + plist_free(client->firmware_preflight_info); + } if (client->preflight_info) { plist_free(client->preflight_info); } @@ -2276,17 +2306,21 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident /* populate parameters */ plist_t parameters = plist_new_dict(); + plist_dict_merge(¶meters, client->parameters); + plist_dict_set_item(parameters, "ApECID", plist_new_uint(client->ecid)); if (client->nonce) { plist_dict_set_item(parameters, "ApNonce", plist_new_data((const char*)client->nonce, client->nonce_size)); } - unsigned char* sep_nonce = NULL; - unsigned int sep_nonce_size = 0; - get_sep_nonce(client, &sep_nonce, &sep_nonce_size); - if (sep_nonce) { - plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); - free(sep_nonce); + if (!plist_dict_get_item(parameters, "SepNonce")) { + unsigned char* sep_nonce = NULL; + unsigned int sep_nonce_size = 0; + get_sep_nonce(client, &sep_nonce, &sep_nonce_size); + if (sep_nonce) { + plist_dict_set_item(parameters, "ApSepNonce", plist_new_data((const char*)sep_nonce, sep_nonce_size)); + free(sep_nonce); + } } plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1)); @@ -2344,7 +2378,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident if (client->mode == MODE_NORMAL) { /* normal mode; request baseband ticket aswell */ plist_t pinfo = NULL; - normal_get_preflight_info(client, &pinfo); + normal_get_firmware_preflight_info(client, &pinfo); if (pinfo) { plist_dict_copy_data(parameters, pinfo, "BbNonce", "Nonce"); plist_dict_copy_uint(parameters, pinfo, "BbChipID", "ChipID"); @@ -2365,6 +2399,10 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident tss_request_add_vinyl_tags(request, parameters, NULL); } } + client->firmware_preflight_info = pinfo; + pinfo = NULL; + + normal_get_preflight_info(client, &pinfo); client->preflight_info = pinfo; } @@ -2718,7 +2756,7 @@ int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** com return 0; } -int personalize_component(const char *component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size) +int personalize_component(struct idevicerestore_client_t* client, const char *component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size) { unsigned char* component_blob = NULL; unsigned int component_blob_size = 0; @@ -2727,7 +2765,7 @@ int personalize_component(const char *component_name, const unsigned char* compo if (tss_response && plist_dict_get_item(tss_response, "ApImg4Ticket")) { /* stitch ApImg4Ticket into IMG4 file */ - img4_stitch_component(component_name, component_data, component_size, tss_response, &stitched_component, &stitched_component_size); + img4_stitch_component(component_name, component_data, component_size, client->parameters, tss_response, &stitched_component, &stitched_component_size); } else { /* try to get blob for current component from tss response */ if (tss_response && tss_response_get_blob_by_entry(tss_response, component_name, &component_blob) < 0) { diff --git a/src/idevicerestore.h b/src/idevicerestore.h index 5afcf1af..fe9d11f2 100644 --- a/src/idevicerestore.h +++ b/src/idevicerestore.h @@ -115,7 +115,7 @@ int build_identity_has_component(plist_t build_identity, const char* component); int build_identity_get_component_path(plist_t build_identity, const char* component, char** path); int ipsw_extract_filesystem(ipsw_archive_t ipsw, plist_t build_identity, char** filesystem); int extract_component(ipsw_archive_t ipsw, const char* path, unsigned char** component_data, unsigned int* component_size); -int personalize_component(const char *component, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size); +int personalize_component(struct idevicerestore_client_t* client, const char *component, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** personalized_component, unsigned int* personalized_component_size); int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* manifest); const char* get_component_name(const char* filename); diff --git a/src/img4.c b/src/img4.c index c010ce4f..e9d4ccac 100644 --- a/src/img4.c +++ b/src/img4.c @@ -26,6 +26,7 @@ #include "common.h" #include "img4.h" +#include "endianness.h" #define ASN1_PRIVATE 0xc0 #define ASN1_PRIMITIVE_TAG 0x1f @@ -395,7 +396,7 @@ static const char *_img4_get_component_tag(const char *compname) return NULL; } -int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size) +int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t parameters, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size) { unsigned char* magic_header = NULL; unsigned int magic_header_size = 0; @@ -459,14 +460,17 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo snprintf(tbm_key, strlen(component_name)+5, "%s-TBM", component_name); plist_t tbm_dict = plist_dict_get_item(tss_response, tbm_key); free(tbm_key); + uint64_t ucon_size = 0; + const char* ucon_data = NULL; + uint64_t ucer_size = 0; + const char* ucer_data = NULL; if (tbm_dict) { plist_t dt = plist_dict_get_item(tbm_dict, "ucon"); if (!dt) { error("ERROR: %s: Missing ucon node in %s-TBM dictionary\n", __func__, component_name); return -1; } - uint64_t ucon_size = 0; - const char* ucon_data = plist_get_data_ptr(dt, &ucon_size); + ucon_data = plist_get_data_ptr(dt, &ucon_size); if (!ucon_data) { error("ERROR: %s: Missing ucon data in %s-TBM dictionary\n", __func__, component_name); return -1; @@ -476,76 +480,141 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo error("ERROR: %s: Missing ucer data node in %s-TBM dictionary\n", __func__, component_name); return -1; } - uint64_t ucer_size = 0; - const char* ucer_data = plist_get_data_ptr(dt, &ucer_size); + ucer_data = plist_get_data_ptr(dt, &ucer_size); if (!ucer_data) { error("ERROR: %s: Missing ucer data in %s-TBM dictionary\n", __func__, component_name); return -1; } + } + + int nonce_slot_required = plist_dict_get_bool(parameters, "RequiresNonceSlot") && (!strcmp(component_name, "SEP") || !strcmp(component_name, "SepStage1") || !strcmp(component_name, "LLB")); - unsigned char *im4rset = (unsigned char*)malloc(16 + 8 + 8 + ucon_size + 16 + 8 + 8 + ucer_size + 16); + if (ucon_data || ucer_data || nonce_slot_required) { + size_t im4r_size = 16; + if (ucon_data) { + im4r_size += 8 + 8 + ucon_size + 16; + } + if (ucer_data) { + im4r_size += 8 + 8 + ucer_size + 16; + } + if (nonce_slot_required) { + im4r_size += 16; + } + unsigned char *im4rset = (unsigned char*)malloc(im4r_size); unsigned char *p_im4rset = im4rset; unsigned int im4rlen = 0; + // ----------- anid/snid ------- + if (nonce_slot_required) { + const char* tag_name = NULL; + uint64_t tag_value = 0; + if (!strcmp(component_name, "SEP") || !strcmp(component_name, "SepStage1")) { + tag_name = "snid"; + tag_value = 2; + if (plist_dict_get_item(parameters, "SepNonceSlotID")) { + tag_value = plist_dict_get_uint(parameters, "SepNonceSlotID"); + } + } else { + tag_name = "anid"; + tag_value = 0; + if (plist_dict_get_item(parameters, "ApNonceSlotID")) { + tag_value = plist_dict_get_uint(parameters, "ApNonceSlotID"); + } + } + // write priv anid/snid element + asn1_write_priv_element(&p_im4rset, &im4rlen, __bswap_32(*(uint32_t*)tag_name)); + // write anid/snid IA5STRING and anid/snid value + unsigned char inner_seq[16]; + unsigned char *p_inner_seq = &inner_seq[0]; + unsigned int inner_seq_hdr_len = 0; + asn1_write_element(&p_inner_seq, &inner_seq_hdr_len, ASN1_IA5_STRING, (void*)tag_name, -1); + asn1_write_element(&p_inner_seq, &inner_seq_hdr_len, ASN1_INTEGER, (void*)&tag_value, -1); + + // write anid/snid sequence + unsigned char elem_seq[8]; + unsigned char *p = &elem_seq[0]; + unsigned int seq_hdr_len = 0; + asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, inner_seq_hdr_len, &p, &seq_hdr_len); + + // add size to priv anid/snid element + asn1_write_size(inner_seq_hdr_len + seq_hdr_len, &p_im4rset, &im4rlen); + + // put it together + memcpy(p_im4rset, elem_seq, seq_hdr_len); + p_im4rset += seq_hdr_len; + im4rlen += seq_hdr_len; + memcpy(p_im4rset, inner_seq, inner_seq_hdr_len); + p_im4rset += inner_seq_hdr_len; + im4rlen += inner_seq_hdr_len; + } + // ----------- ucon ------------ - // write priv ucon element - asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"nocu"); - - // write ucon IA5STRING and ucon data - unsigned char ucon_seq[16]; - unsigned char *p_ucon_seq = &ucon_seq[0]; - unsigned int ucon_seq_hdr_len = 0; - asn1_write_element(&p_ucon_seq, &ucon_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucon", -1); - asn1_write_element_header(ASN1_OCTET_STRING, ucon_size, &p_ucon_seq, &ucon_seq_hdr_len); - - // write ucon sequence - unsigned char elem_seq[8]; - unsigned char *p = &elem_seq[0]; - unsigned int seq_hdr_len = 0; - asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, ucon_seq_hdr_len + ucon_size, &p, &seq_hdr_len); - - // add size to priv ucon element - asn1_write_size(ucon_seq_hdr_len + ucon_size + seq_hdr_len, &p_im4rset, &im4rlen); - - // put it together - memcpy(p_im4rset, elem_seq, seq_hdr_len); - p_im4rset += seq_hdr_len; - im4rlen += seq_hdr_len; - memcpy(p_im4rset, ucon_seq, ucon_seq_hdr_len); - p_im4rset += ucon_seq_hdr_len; - im4rlen += ucon_seq_hdr_len; - memcpy(p_im4rset, ucon_data, ucon_size); - p_im4rset += ucon_size; - im4rlen += ucon_size; + if (ucon_data) { + // write priv ucon element + asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"nocu"); + + // write ucon IA5STRING and ucon data header + unsigned char inner_seq[16]; + unsigned char *p_inner_seq = &inner_seq[0]; + unsigned int inner_seq_hdr_len = 0; + asn1_write_element(&p_inner_seq, &inner_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucon", -1); + asn1_write_element_header(ASN1_OCTET_STRING, ucon_size, &p_inner_seq, &inner_seq_hdr_len); + + // write ucon sequence + unsigned char elem_seq[8]; + unsigned char *p = &elem_seq[0]; + unsigned int seq_hdr_len = 0; + asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, inner_seq_hdr_len + ucon_size, &p, &seq_hdr_len); + + // add size to priv ucon element + asn1_write_size(inner_seq_hdr_len + ucon_size + seq_hdr_len, &p_im4rset, &im4rlen); + + // put it together + memcpy(p_im4rset, elem_seq, seq_hdr_len); + p_im4rset += seq_hdr_len; + im4rlen += seq_hdr_len; + memcpy(p_im4rset, inner_seq, inner_seq_hdr_len); + p_im4rset += inner_seq_hdr_len; + im4rlen += inner_seq_hdr_len; + // write ucon data + memcpy(p_im4rset, ucon_data, ucon_size); + p_im4rset += ucon_size; + im4rlen += ucon_size; + } // ----------- ucer ------------ - // write priv ucer element - asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"recu"); - - // write ucon IA5STRING and ucer data - unsigned char ucer_seq[16]; - unsigned char *p_ucer_seq = &ucer_seq[0]; - unsigned int ucer_seq_hdr_len = 0; - asn1_write_element(&p_ucer_seq, &ucer_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucer", -1); - asn1_write_element_header(ASN1_OCTET_STRING, ucer_size, &p_ucer_seq, &ucer_seq_hdr_len); - - p = &elem_seq[0]; - seq_hdr_len = 0; - asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, ucer_seq_hdr_len + ucer_size, &p, &seq_hdr_len); - - // add size to priv ucer element - asn1_write_size(ucer_seq_hdr_len + ucer_size + seq_hdr_len, &p_im4rset, &im4rlen); - - // put it together - memcpy(p_im4rset, elem_seq, seq_hdr_len); - p_im4rset += seq_hdr_len; - im4rlen += seq_hdr_len; - memcpy(p_im4rset, ucer_seq, ucer_seq_hdr_len); - p_im4rset += ucer_seq_hdr_len; - im4rlen += ucer_seq_hdr_len; - memcpy(p_im4rset, ucer_data, ucer_size); - p_im4rset += ucer_size; - im4rlen += ucer_size; + if (ucer_data) { + // write priv ucer element + asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"recu"); + + // write ucer IA5STRING and ucer data header + unsigned char inner_seq[16]; + unsigned char *p_inner_seq = &inner_seq[0]; + unsigned int inner_seq_hdr_len = 0; + asn1_write_element(&p_inner_seq, &inner_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucer", -1); + asn1_write_element_header(ASN1_OCTET_STRING, ucer_size, &p_inner_seq, &inner_seq_hdr_len); + + // write ucer sequence + unsigned char elem_seq[8]; + unsigned char *p = &elem_seq[0]; + unsigned int seq_hdr_len = 0; + asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, inner_seq_hdr_len + ucer_size, &p, &seq_hdr_len); + + // add size to priv ucer element + asn1_write_size(inner_seq_hdr_len + ucer_size + seq_hdr_len, &p_im4rset, &im4rlen); + + // put it together + memcpy(p_im4rset, elem_seq, seq_hdr_len); + p_im4rset += seq_hdr_len; + im4rlen += seq_hdr_len; + memcpy(p_im4rset, inner_seq, inner_seq_hdr_len); + p_im4rset += inner_seq_hdr_len; + im4rlen += inner_seq_hdr_len; + // write ucer data + memcpy(p_im4rset, ucer_data, ucer_size); + p_im4rset += ucer_size; + im4rlen += ucer_size; + } // now construct IM4R diff --git a/src/img4.h b/src/img4.h index 1056fa68..19c1c84e 100644 --- a/src/img4.h +++ b/src/img4.h @@ -26,7 +26,7 @@ extern "C" { #endif -int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size); +int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, plist_t parameters, plist_t tss_response, unsigned char** img4_data, unsigned int *img4_size); int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* manifest); #ifdef __cplusplus diff --git a/src/normal.c b/src/normal.c index e699bbe6..9e460803 100644 --- a/src/normal.c +++ b/src/normal.c @@ -342,6 +342,18 @@ static int normal_get_nonce_by_key(struct idevicerestore_client_t* client, const int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { + plist_t node = normal_get_lockdown_value(client, NULL, "ApParameters"); + if (PLIST_IS_DICT(node)) { + plist_t nonce_node = plist_dict_get_item(node, "SepNonce"); + if (nonce_node) { + uint64_t n_size = 0; + plist_get_data_val(nonce_node, (char**)nonce, &n_size); + *nonce_size = (unsigned int)n_size; + plist_free(node); + return 0; + } + } + plist_free(node); return normal_get_nonce_by_key(client, "SEPNonce", nonce, nonce_size); } @@ -365,7 +377,7 @@ int normal_is_image4_supported(struct idevicerestore_client_t* client) return bval; } -int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info) +int normal_get_firmware_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info) { uint8_t has_telephony_capability = 0; plist_t node; @@ -389,6 +401,18 @@ int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *p return 0; } +int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info) +{ + plist_t node = normal_get_lockdown_value(client, NULL, "PreflightInfo"); + if (PLIST_IS_DICT(node)) { + *preflight_info = node; + } else { + debug("DEBUG: No PreflightInfo available.\n"); + *preflight_info = NULL; + } + return 0; +} + int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_t manifest) { int result = -1; diff --git a/src/normal.h b/src/normal.h index 7741ac5f..d3d7b0cd 100644 --- a/src/normal.h +++ b/src/normal.h @@ -38,6 +38,7 @@ int normal_enter_recovery(struct idevicerestore_client_t* client); int normal_is_image4_supported(struct idevicerestore_client_t* client); int normal_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); int normal_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size); +int normal_get_firmware_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info); int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info); plist_t normal_get_lockdown_value(struct idevicerestore_client_t* client, const char* domain, const char* key); int normal_handle_create_stashbag(struct idevicerestore_client_t* client, plist_t manifest); diff --git a/src/recovery.c b/src/recovery.c index afda4a97..c4513502 100644 --- a/src/recovery.c +++ b/src/recovery.c @@ -305,7 +305,7 @@ int recovery_send_component(struct idevicerestore_client_t* client, plist_t buil return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size); free(component_data); if (ret < 0) { error("ERROR: Unable to get personalized component: %s\n", component); diff --git a/src/restore.c b/src/restore.c index 6fdf755e..2daeea2b 100644 --- a/src/restore.c +++ b/src/restore.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -1490,7 +1491,7 @@ int restore_send_component(struct idevicerestore_client_t* client, plist_t messa return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size); free(component_data); component_data = NULL; if (ret < 0) { @@ -1662,7 +1663,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &llb_data, &llb_size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &llb_data, &llb_size); free(component_data); component_data = NULL; component_size = 0; @@ -1718,7 +1719,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) return -1; } - if (personalize_component(component, component_data, component_size, client->tss, &nor_data, &nor_size) < 0) { + if (personalize_component(client, component, component_data, component_size, client->tss, &nor_data, &nor_size) < 0) { free(iter); free(comp); free(comppath); @@ -1765,7 +1766,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &personalized_data, &personalized_size); free(component_data); component_data = NULL; component_size = 0; @@ -1790,7 +1791,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &personalized_data, &personalized_size); free(component_data); component_data = NULL; component_size = 0; @@ -1815,7 +1816,7 @@ int restore_send_nor(struct idevicerestore_client_t* client, plist_t message) return -1; } - ret = personalize_component(component, component_data, component_size, client->tss, &personalized_data, &personalized_size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &personalized_data, &personalized_size); free(component_data); component_data = NULL; component_size = 0; @@ -2518,7 +2519,7 @@ static int restore_send_image_data(struct idevicerestore_client_t *client, plist error("ERROR: Unable to extract component: %s\n", component); } - ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size); free(component_data); component_data = NULL; if (ret < 0) { @@ -4273,7 +4274,7 @@ int restore_send_personalized_boot_object_v3(struct idevicerestore_client_t* cli } // Personalize IMG4 - ret = personalize_component(component, component_data, component_size, client->tss, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss, &data, &size); free(component_data); component_data = NULL; if (ret < 0) { @@ -4439,7 +4440,7 @@ int restore_send_restore_local_policy(struct idevicerestore_client_t* client, pl return -1; } - ret = personalize_component(component, component_data, component_size, client->tss_localpolicy, &data, &size); + ret = personalize_component(client, component, component_data, component_size, client->tss_localpolicy, &data, &size); free(component_data); component_data = NULL; if (ret < 0) { @@ -4508,6 +4509,232 @@ int restore_send_buildidentity(struct idevicerestore_client_t* client, plist_t m return 0; } +int restore_send_recovery_os_file_asset_image(struct idevicerestore_client_t* client, plist_t message) +{ + char *fw_override_key = NULL; + plist_t node = plist_access_path(message, 2, "Arguments", "FWOverrideKey"); + if (PLIST_IS_STRING(node)) { + plist_get_string_val(node, &fw_override_key); + } + if (!fw_override_key) { + error("ERROR: Failed to get FWOverrideKey from arguments. Trying to continue anyway.\n"); + return -1; + } + + plist_t dict = plist_new_dict(); + if (!client->recovery_variant) { + error("ERROR: no RecoveryOS variant in BuildManifest. Trying to continue anyway.\n"); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + if (strncmp(fw_override_key, "RecoveryOS", 10) != 0) { + error("ERROR: FWOVerrideKey has unexpected prefix\n"); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + const char* component = fw_override_key+10; + char* path = NULL; + if (build_identity_get_component_path(client->recovery_variant, component, &path) < 0) { + error("ERROR: Unable to find %s path from recovery build identity. Trying to continue anyway.\n", component); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + unsigned char* component_data = NULL; + unsigned int component_size = 0; + int ret = extract_component(client->ipsw, path, &component_data, &component_size); + free(path); + path = NULL; + if (ret < 0) { + error("ERROR: Unable to extract component %s. Trying to continue anyway.\n", component); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + unsigned char* data = NULL; + unsigned int size = 0; + ret = personalize_component(client, component, component_data, component_size, client->tss_recoveryos_root_ticket, &data, &size); + free(component_data); + component_data = NULL; + if (ret < 0) { + error("ERROR: Unable to get personalized component %s. Trying to continue anyway.\n", component); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + } + + info("Sending %s\n", fw_override_key); + + plist_dict_set_item(dict, "AdditionalBootImages", plist_new_data((char*)data, size)); + free(data); + restored_send(client->restore->client, dict); + plist_free(dict); + + return 0; +} + +int restore_send_recovery_os_iboot_fw_files_images(struct idevicerestore_client_t* client, plist_t message) +{ + plist_t build_id_manifest = plist_dict_get_item(client->recovery_variant, "Manifest"); + if (!build_id_manifest) { + error("ERROR: Missing Manifest dictionary in build identity?!\n"); + return -1; + } + + plist_t firmware_files = plist_new_dict(); + + plist_dict_iter iter = NULL; + plist_dict_new_iter(build_id_manifest, &iter); + if (iter) { + char *component = NULL; + plist_t manifest_entry; + do { + component = NULL; + manifest_entry = NULL; + plist_dict_next_item(build_id_manifest, iter, &component, &manifest_entry); + if (component && PLIST_IS_DICT(manifest_entry)) { + uint8_t loaded_by_iboot = 0; + uint8_t loaded_by_iboot_stage1 = 0; + plist_t fw_node; + + fw_node = plist_access_path(manifest_entry, 2, "Info", "IsLoadedByiBoot"); + if (fw_node && plist_get_node_type(fw_node) == PLIST_BOOLEAN) { + plist_get_bool_val(fw_node, &loaded_by_iboot); + } + fw_node = plist_access_path(manifest_entry, 2, "Info", "IsLoadedByiBootStage1"); + if (fw_node && plist_get_node_type(fw_node) == PLIST_BOOLEAN) { + plist_get_bool_val(fw_node, &loaded_by_iboot_stage1); + } + if (loaded_by_iboot || loaded_by_iboot_stage1) { + plist_t comp_path = plist_access_path(manifest_entry, 2, "Info", "Path"); + if (comp_path) { + const char* path = plist_get_string_ptr(comp_path, NULL); + unsigned char* component_data = NULL; + unsigned int component_size = 0; + int ret = extract_component(client->ipsw, path, &component_data, &component_size); + if (ret == 0) { + unsigned char* data = NULL; + unsigned int size = 0; + ret = personalize_component(client, component, component_data, component_size, client->tss_recoveryos_root_ticket, &data, &size); + free(component_data); + component_data = NULL; + if (ret == 0) { + plist_dict_set_item(firmware_files, component, plist_new_data((char*)data, size)); + free(data); + } + } + } + } + } + free(component); + } while (manifest_entry); + plist_mem_free(iter); + } + + plist_t dict = plist_new_dict(); + + if (plist_dict_get_size(firmware_files) == 0) { + plist_free(firmware_files); + info("NOTE: No iBoot firmware files. Continuing.\n"); + plist_dict_set_item(dict, "RecoveryOSNoAssetFound", plist_new_bool(1)); + restored_send(client->restore->client, dict); + plist_free(dict); + return 0; + + } + + info("Sending iBoot additional firmware files\n"); + + plist_dict_set_item(dict, "AdditionalBootImages", firmware_files); + restored_send(client->restore->client, dict); + plist_free(dict); + + return 0; +} + +int restore_send_recovery_os_image(struct idevicerestore_client_t* client, plist_t message) +{ + const char* component = "OS"; + char* path = NULL; + if (build_identity_get_component_path(client->recovery_variant, component, &path) < 0) { + error("ERROR: Unable to find %s path from build identity\n", component); + return -1; + } + if (!path) { + error("ERROR: Failed to get path for component %s\n", component); + return -1; + } + + uint64_t fsize = 0; + ipsw_get_file_size(client->ipsw, path, &fsize); + + restore_service_client_t service = _restore_get_service_client_for_data_request(client, message); + if (!service) { + error("ERROR: %s: Unable to connect to service client\n", __func__); + return -1; + } + + info("Sending %s now (%" PRIu64 " bytes)\n", component, fsize); + + struct _restore_send_file_data_ctx rctx; + rctx.client = client; + rctx.service = service; + rctx.last_progress = 0; + + if (ipsw_extract_send(client->ipsw, path, 8192, (ipsw_send_cb)_restore_send_file_data, &rctx) < 0) { + free(path); + _restore_service_free(service); + error("ERROR: Failed to send component %s\n", component); + return -1; + } + free(path); + + _restore_service_free(service); + + info("Done sending %s\n", component); + + return 0; +} + +int restore_send_recovery_os_version_data(struct idevicerestore_client_t* client, plist_t message) +{ + plist_t build_id_info = plist_dict_get_item(client->recovery_variant, "Info"); + if (!build_id_info) { + error("ERROR: Missing Info dictionary in build identity?!\n"); + return -1; + } + plist_t version_data = plist_new_dict(); + plist_dict_copy_item(version_data, build_id_info, "BuildNumber", NULL); + plist_dict_copy_item(version_data, build_id_info, "Variant", NULL); + plist_dict_copy_item(version_data, build_id_info, "BuildTrain", NULL); + plist_dict_copy_item(version_data, build_id_info, "ProductVersion", "ProductMarketingVersion"); + char *xml = NULL; + uint32_t xml_len = 0; + plist_to_xml(version_data, &xml, &xml_len); + plist_free(version_data); + + info("Sending RecoveryOS version data\n"); + + plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "RecoveryOSVersionData", plist_new_data(xml, xml_len)); + plist_mem_free(xml); + restored_send(client->restore->client, dict); + plist_free(dict); + + return 0; +} + int restore_handle_data_request_msg(struct idevicerestore_client_t* client, plist_t message) { plist_t node = NULL; @@ -4702,6 +4929,34 @@ debug("%s: type = %s\n", __func__, type); } } + else if (!strcmp(type, "RecoveryOSFileAssetImage")) { + if (restore_send_recovery_os_file_asset_image(client, message) < 0) { + error("ERROR: Unable to send RecoveryOSFileImageAssetImage data\n"); + return -1; + } + } + + else if (!strcmp(type, "RecoveryOSIBootFWFilesImages")) { + if (restore_send_recovery_os_iboot_fw_files_images(client, message) < 0) { + error("ERROR: Unable to send RecoveryOSIBootFWFilesImages data\n"); + return -1; + } + } + + else if (!strcmp(type, "RecoveryOSImage")) { + if (restore_send_recovery_os_image(client, message) < 0) { + error("ERROR: Unable to send RecoveryOSImage data\n"); + return -1; + } + } + + else if (!strcmp(type, "RecoveryOSVersionData")) { + if (restore_send_recovery_os_version_data(client, message) < 0) { + error("ERROR: Unable to send RecoveryOSVersionData data\n"); + return -1; + } + } + else { // Unknown DataType!! error("Unknown data request '%s' received\n", type); @@ -4776,10 +5031,70 @@ static int restore_handle_restore_attestation(struct idevicerestore_client_t* cl return 0; } +static void _restore_calculate_recovery_os_partition_size(struct idevicerestore_client_t* client, uint64_t* min_size, uint64_t* max_size) +{ + const char* asset_list[] = { "OS", "KernelCache", "DeviceTree", "iBEC", "AppleLogo", "StaticTrustCache", "iBootData", "Diags", "Ap,SystemVolumeCanonicalMetadata", "SystemVolume", "BaseSystemVolume", "Ap,BaseSystemTrustCache", "AVISP1,RTKitOS", NULL }; + + if (min_size) *min_size = 356; + if (max_size) *max_size = 420; + + double total_size = 0; + plist_t firmware_items = plist_new_dict(); + plist_t build_id_manifest = plist_dict_get_item(client->recovery_variant, "Manifest"); + plist_dict_iter iter = NULL; + plist_dict_new_iter(build_id_manifest, &iter); + if (iter) { + char *component = NULL; + plist_t manifest_entry; + do { + component = NULL; + manifest_entry = NULL; + plist_dict_next_item(build_id_manifest, iter, &component, &manifest_entry); + if (component && PLIST_IS_DICT(manifest_entry) && plist_dict_get_item(firmware_items, component) == NULL) { + int add_image = 0; + int i = 0; + while (asset_list[i]) { + if (!strcmp(asset_list[i], component)) { + add_image = 1; + break; + } + i++; + } + plist_t fw_node; + fw_node = plist_access_path(manifest_entry, 2, "Info", "IsLoadedByiBoot"); + if (fw_node && plist_get_node_type(fw_node) == PLIST_BOOLEAN) { + uint8_t loaded_by_iboot = 0; + plist_get_bool_val(fw_node, &loaded_by_iboot); + if (loaded_by_iboot) { + add_image = 1; + } + } + if (add_image) { + plist_t p_path = plist_access_path(manifest_entry, 2, "Info", "Path"); + if (p_path) { + const char* path = plist_get_string_ptr(p_path, NULL); + uint64_t fsize = 0; + if (ipsw_get_file_size(client->ipsw, path, &fsize) == 0) { + debug("%s: Adding %s (%s, %llu bytes)\n", __func__, component, path, fsize); + total_size += (double)fsize / 0x100000; + } + } + } + } + free(component); + } while (manifest_entry); + plist_mem_free(iter); + } + total_size = ceil(total_size); + if (min_size) *min_size = total_size * 1.05 + 25; + if (max_size) *max_size = total_size * 1.25 + 25; +} + // Extracted from ac2 plist_t restore_supported_data_types() { plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "AuthInstallCACert", plist_new_bool(1)); plist_dict_set_item(dict, "BasebandBootData", plist_new_bool(0)); plist_dict_set_item(dict, "BasebandData", plist_new_bool(0)); plist_dict_set_item(dict, "BasebandStackData", plist_new_bool(0)); @@ -4797,20 +5112,26 @@ plist_t restore_supported_data_types() plist_dict_set_item(dict, "FileData", plist_new_bool(0)); plist_dict_set_item(dict, "FileDataDone", plist_new_bool(0)); plist_dict_set_item(dict, "FirmwareUpdaterData", plist_new_bool(0)); + plist_dict_set_item(dict, "FirmwareUpdaterDataV2", plist_new_bool(0)); + plist_dict_set_item(dict, "FirmwareUpdaterDataV3", plist_new_bool(1)); + plist_dict_set_item(dict, "FirmwareUpdaterPreflight", plist_new_bool(1)); plist_dict_set_item(dict, "GrapeFWData", plist_new_bool(0)); plist_dict_set_item(dict, "HPMFWData", plist_new_bool(0)); plist_dict_set_item(dict, "HostSystemTime", plist_new_bool(1)); plist_dict_set_item(dict, "KernelCache", plist_new_bool(0)); + plist_dict_set_item(dict, "MessageUseStreamedImageFile", plist_new_bool(1)); plist_dict_set_item(dict, "NORData", plist_new_bool(0)); plist_dict_set_item(dict, "NitrogenFWData", plist_new_bool(1)); plist_dict_set_item(dict, "OpalFWData", plist_new_bool(0)); plist_dict_set_item(dict, "OverlayRootDataCount", plist_new_bool(0)); plist_dict_set_item(dict, "OverlayRootDataForKey", plist_new_bool(1)); + plist_dict_set_item(dict, "OverlayRootDataForKeyIndex", plist_new_bool(1)); plist_dict_set_item(dict, "PeppyFWData", plist_new_bool(1)); plist_dict_set_item(dict, "PersonalizedBootObjectV3", plist_new_bool(0)); plist_dict_set_item(dict, "PersonalizedData", plist_new_bool(1)); plist_dict_set_item(dict, "ProvisioningData", plist_new_bool(0)); plist_dict_set_item(dict, "RamdiskFWData", plist_new_bool(1)); + plist_dict_set_item(dict, "ReceiptManifest", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSASRImage", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSAppleLogo", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSDeviceTree", plist_new_bool(1)); @@ -4824,6 +5145,7 @@ plist_t restore_supported_data_types() plist_dict_set_item(dict, "RecoveryOSRootTicketData", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSStaticTrustCache", plist_new_bool(1)); plist_dict_set_item(dict, "RecoveryOSVersionData", plist_new_bool(1)); + plist_dict_set_item(dict, "RestoreLocalPolicy", plist_new_bool(1)); plist_dict_set_item(dict, "RootData", plist_new_bool(0)); plist_dict_set_item(dict, "RootTicket", plist_new_bool(0)); plist_dict_set_item(dict, "S3EOverride", plist_new_bool(0)); @@ -4834,18 +5156,10 @@ plist_t restore_supported_data_types() plist_dict_set_item(dict, "SystemImageCanonicalMetadata", plist_new_bool(0)); plist_dict_set_item(dict, "SystemImageData", plist_new_bool(0)); plist_dict_set_item(dict, "SystemImageRootHash", plist_new_bool(0)); + plist_dict_set_item(dict, "URLAsset", plist_new_bool(1)); plist_dict_set_item(dict, "USBCFWData", plist_new_bool(0)); plist_dict_set_item(dict, "USBCOverride", plist_new_bool(0)); - plist_dict_set_item(dict, "FirmwareUpdaterPreflight", plist_new_bool(1)); - plist_dict_set_item(dict, "ReceiptManifest", plist_new_bool(1)); - plist_dict_set_item(dict, "FirmwareUpdaterDataV2", plist_new_bool(0)); - plist_dict_set_item(dict, "RestoreLocalPolicy", plist_new_bool(1)); - plist_dict_set_item(dict, "AuthInstallCACert", plist_new_bool(1)); - plist_dict_set_item(dict, "OverlayRootDataForKeyIndex", plist_new_bool(1)); - plist_dict_set_item(dict, "FirmwareUpdaterDataV3", plist_new_bool(1)); - plist_dict_set_item(dict, "MessageUseStreamedImageFile", plist_new_bool(1)); plist_dict_set_item(dict, "UpdateVolumeOverlayRootDataCount", plist_new_bool(1)); - plist_dict_set_item(dict, "URLAsset", plist_new_bool(1)); return dict; } @@ -4853,8 +5167,11 @@ plist_t restore_supported_data_types() plist_t restore_supported_message_types() { plist_t dict = plist_new_dict(); + plist_dict_set_item(dict, "AsyncDataRequestMsg", plist_new_bool(1)); + plist_dict_set_item(dict, "AsyncWait", plist_new_bool(1)); plist_dict_set_item(dict, "BBUpdateStatusMsg", plist_new_bool(0)); plist_dict_set_item(dict, "CheckpointMsg", plist_new_bool(1)); + plist_dict_set_item(dict, "CrashLog", plist_new_bool(1)); plist_dict_set_item(dict, "DataRequestMsg", plist_new_bool(0)); plist_dict_set_item(dict, "FDRSubmit", plist_new_bool(1)); plist_dict_set_item(dict, "MsgType", plist_new_bool(0)); @@ -4864,11 +5181,9 @@ plist_t restore_supported_message_types() plist_dict_set_item(dict, "ProvisioningInfo", plist_new_bool(0)); plist_dict_set_item(dict, "ProvisioningStatusMsg", plist_new_bool(0)); plist_dict_set_item(dict, "ReceivedFinalStatusMsg", plist_new_bool(0)); + plist_dict_set_item(dict, "RestoreAttestation", plist_new_bool(1)); plist_dict_set_item(dict, "RestoredCrash", plist_new_bool(1)); plist_dict_set_item(dict, "StatusMsg", plist_new_bool(0)); - plist_dict_set_item(dict, "AsyncDataRequestMsg", plist_new_bool(1)); - plist_dict_set_item(dict, "AsyncWait", plist_new_bool(1)); - plist_dict_set_item(dict, "RestoreAttestation", plist_new_bool(1)); return dict; } @@ -5024,15 +5339,15 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit //plist_dict_set_item(opts, "AuthInstallRestoreBehavior", plist_new_string("Erase")); plist_dict_set_item(opts, "AutoBootDelay", plist_new_uint(0)); - if (client->preflight_info) { - plist_t bbus = plist_copy(client->preflight_info); + if (client->firmware_preflight_info) { + plist_t bbus = plist_copy(client->firmware_preflight_info); plist_dict_remove_item(bbus, "FusingStatus"); plist_dict_remove_item(bbus, "PkHash"); plist_dict_set_item(opts, "BBUpdaterState", bbus); - plist_dict_copy_data(opts, client->preflight_info, "BasebandNonce", "Nonce"); + plist_dict_copy_data(opts, client->firmware_preflight_info, "BasebandNonce", "Nonce"); } plist_dict_set_item(opts, "SupportedDataTypes", restore_supported_data_types()); @@ -5078,7 +5393,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit } } else { // FIXME: new on iOS 5 ? - plist_dict_set_item(opts, "BootImageType", plist_new_string("UserOrInternal")); + plist_dict_set_item(opts, "BootImageType", plist_new_string("User")); // FIXME: required? //plist_dict_set_item(opts, "BootImageFile", plist_new_string("018-7923-347.dmg")); plist_dict_set_item(opts, "DFUFileType", plist_new_string("RELEASE")); @@ -5104,7 +5419,27 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit // FIXME: new on iOS 5 ? plist_dict_set_item(opts, "SystemImageType", plist_new_string("User")); // FIXME: does this have any effect actually? - plist_dict_set_item(opts, "UpdateBaseband", plist_new_bool(0)); + plist_dict_set_item(opts, "UpdateBaseband", plist_new_bool(1)); + plist_dict_set_item(opts, "InstallDiags", plist_new_bool(0)); + if (client->recovery_variant) { + plist_dict_set_item(opts, "InstallRecoveryOS", plist_new_bool(1)); + plist_dict_set_item(opts, "RecoveryOSBundlePath", plist_new_string("/tmp/Per2.tmp")); + plist_t recovery_variant = plist_access_path(client->recovery_variant, 2, "Info", "Variant"); + plist_dict_set_item(opts, "AuthInstallRecoveryOSVariant", plist_copy(recovery_variant)); + uint64_t max_size = 0; + uint64_t min_size = 0; + _restore_calculate_recovery_os_partition_size(client, &min_size, &max_size); + info("Calculated recoveryOSPartitionSize as %" PRIu64 " MB\n", min_size); + info("Calculated recoveryOSMaxPartitionSize as %" PRIu64 " MB\n", max_size); + plist_dict_set_item(opts, "recoveryOSMaxPartitionSize", plist_new_uint(max_size)); + plist_dict_set_item(opts, "recoveryOSPartitionSize", plist_new_uint(min_size)); + } + + if (plist_dict_get_bool(client->parameters, "RequiresNonceSlot")) { + info("Device will use nonce slots.\n"); + } else { + info("Device will not use nonce slots.\n"); + } // Added for iOS 18.0 beta 1 plist_dict_set_item(opts, "HostHasFixFor99053849", plist_new_bool(1)); @@ -5154,10 +5489,14 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit spp = plist_copy(spp); } else { spp = plist_new_dict(); + plist_dict_set_item(spp, "1024", plist_new_uint(1280)); plist_dict_set_item(spp, "128", plist_new_uint(1280)); plist_dict_set_item(spp, "16", plist_new_uint(160)); + plist_dict_set_item(spp, "256", plist_new_uint(1280)); plist_dict_set_item(spp, "32", plist_new_uint(320)); + plist_dict_set_item(spp, "512", plist_new_uint(1280)); plist_dict_set_item(spp, "64", plist_new_uint(640)); + plist_dict_set_item(spp, "768", plist_new_uint(1280)); plist_dict_set_item(spp, "8", plist_new_uint(80)); } plist_dict_set_item(opts, "SystemPartitionPadding", spp); From 559adb735debcd9743569763a3d51270008310e1 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 22 Oct 2024 19:33:22 +0200 Subject: [PATCH 113/117] Updated README --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1af2d935..c7d22d6c 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,10 @@ Only the prerequisites differ and they are described in this section. make \ libtool \ autoconf \ - automake-wrapper + automake-wrapper \ + pkg-config \ + libcurl-devel \ + mingw-w64-x86_64-libzip ``` NOTE: You can use a different shell and different compiler according to your needs. Adapt the above command accordingly. @@ -280,8 +283,8 @@ Please make sure your contribution adheres to: ## Links * Homepage: https://libimobiledevice.org/ -* Repository: https://git.libimobiledevice.org/idevicerestore.git -* Repository (Mirror): https://github.com/libimobiledevice/idevicerestore.git +* Repository: https://github.com/libimobiledevice/idevicerestore.git +* Repository (Mirror): https://git.libimobiledevice.org/idevicerestore.git * Issue Tracker: https://github.com/libimobiledevice/idevicerestore/issues * Mailing List: https://lists.libimobiledevice.org/mailman/listinfo/libimobiledevice-devel * Twitter: https://twitter.com/libimobiledev @@ -299,4 +302,4 @@ iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc. This project is an independent software application and has not been authorized, sponsored, or otherwise approved by Apple Inc. -README Updated on: 2024-06-19 +README Updated on: 2024-10-22 From 61a76ce6fc68e9bc14e3bb4ba7a20344afb1e300 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sun, 3 Nov 2024 22:09:51 +0100 Subject: [PATCH 114/117] [github-actions] Update curl workflow to build 8.10.1 for UCRT64 --- .github/workflows/curl.yml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/curl.yml b/.github/workflows/curl.yml index 87e4459b..a1a80167 100644 --- a/.github/workflows/curl.yml +++ b/.github/workflows/curl.yml @@ -12,8 +12,9 @@ jobs: fail-fast: false matrix: include: [ - { msystem: MINGW64, arch: x86_64 }, - { msystem: MINGW32, arch: i686 } + { msystem: UCRT64, arch: x86_64, flavor: w64-ucrt }, + { msystem: MINGW64, arch: x86_64, flavor: w64 }, + { msystem: MINGW32, arch: i686, flavor: w64 } ] steps: - uses: msys2/setup-msys2@v2 @@ -24,12 +25,13 @@ jobs: install: >- base-devel git - mingw-w64-${{ matrix.arch }}-gcc + mingw-${{ matrix.flavor }}-${{ matrix.arch }}-gcc make libtool autoconf automake-wrapper liblzma + mingw-${{ matrix.flavor }}-${{ matrix.arch }}-openssl - name: prepare environment run: | dest=`echo ${{ matrix.msystem }} |tr [:upper:] [:lower:]` @@ -37,22 +39,22 @@ jobs: echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV - name: fetch curl source run: | - curl -Ls -o curl-8.1.0.tar.bz2 https://github.com/curl/curl/releases/download/curl-8_1_0/curl-8.1.0.tar.bz2 - tar xjf curl-8.1.0.tar.bz2 + curl -Ls -o curl-8.10.1.tar.bz2 https://github.com/curl/curl/releases/download/curl-8_10_1/curl-8.10.1.tar.bz2 + tar xjf curl-8.10.1.tar.bz2 - name: configure curl run: | - cd curl-8.1.0 - ./configure --disable-ldap --disable-ldaps --disable-rtsp --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-mqtt --disable-manual --disable-threaded-resolver --disable-pthreads --disable-sspi --disable-aws --disable-ntlm --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --disable-doh --disable-mime --disable-bindlocal --disable-dnsshuffle --disable-alt-svc --disable-hsts --disable-websockets --with-openssl --without-brotli --without-libidn2 --without-ngtcp2 --without-quiche --without-msh3 --without-nghttp2 --without-libpsl + cd curl-8.10.1 + ./configure --disable-ldap --disable-ldaps --disable-rtsp --disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-mqtt --disable-manual --disable-threaded-resolver --disable-pthreads --disable-sspi --disable-aws --disable-ntlm --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --disable-doh --disable-mime --disable-dnsshuffle --disable-alt-svc --disable-hsts --disable-websockets --with-openssl --without-brotli --without-libidn2 --without-ngtcp2 --without-quiche --without-msh3 --without-nghttp2 --without-libpsl - name: build libcurl run: | CURDIR=`pwd` - cd curl-8.1.0/lib + cd curl-8.10.1/lib make cp .libs/libcurl.a . cd .. tar cf $CURDIR/libcurl-static.tar lib/libcurl.a include/curl/*.h - name: publish artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: libcurl_${{ matrix.arch }}-${{ env.dest }} path: libcurl-static.tar From 5d92c7a5875383b81a4d20c479f05b611e54097f Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 2 Dec 2024 06:52:12 +0100 Subject: [PATCH 115/117] [github-actions] Bump dawidd6/action-download-artifact from 3 to 6 --- .github/workflows/build.yml | 42 ++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bd2bdd58..3b7d0dc3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,10 @@ name: build -on: [push] +on: + push: + pull_request: + schedule: + - cron: '0 0 1 * *' jobs: build-linux-ubuntu: @@ -14,42 +18,42 @@ jobs: run: | echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV - name: fetch libirecovery - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libirecovery-latest_${{env.target_triplet}} repo: libimobiledevice/libirecovery - name: fetch libplist - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_${{env.target_triplet}} repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_${{env.target_triplet}} repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_${{env.target_triplet}} repo: libimobiledevice/libimobiledevice-glue - name: fetch libimobiledevice - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-latest_${{env.target_triplet}} repo: libimobiledevice/libimobiledevice - name: fetch libtatsu - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml @@ -95,42 +99,42 @@ jobs: fi shell: bash - name: fetch libirecovery - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libirecovery-latest_macOS repo: libimobiledevice/libirecovery - name: fetch libplist - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_macOS repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_macOS repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_macOS repo: libimobiledevice/libimobiledevice-glue - name: fetch libimobiledevice - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-latest_macOS repo: libimobiledevice/libimobiledevice - name: fetch libtatsu - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml @@ -221,42 +225,42 @@ jobs: echo "dest=$dest" >> $GITHUB_ENV echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV - name: fetch libirecovery - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libirecovery-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libirecovery - name: fetch libplist - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libimobiledevice-glue - name: fetch libimobiledevice - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-latest_${{ matrix.arch }}-${{ env.dest }} repo: libimobiledevice/libimobiledevice - name: fetch libtatsu - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml From 914fbb35f97b37738a93f3f80fb9548bac7afcee Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 2 Dec 2024 06:57:58 +0100 Subject: [PATCH 116/117] Fix build --- src/dfu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dfu.c b/src/dfu.c index e6b45afa..508b4f61 100644 --- a/src/dfu.c +++ b/src/dfu.c @@ -84,7 +84,6 @@ irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client) irecv_error_t dfu_error = IRECV_E_SUCCESS; irecv_device_t device = NULL; - irecv_init(); if (irecv_open_with_ecid_and_attempts(&dfu, client->ecid, 10) != IRECV_E_SUCCESS) { return NULL; } From bb5591d690a057fbc6533df2617189005ea95f40 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 3 Dec 2024 01:34:41 +0100 Subject: [PATCH 117/117] configure: Fix Linux build with LTO --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 9d71e956..9c27a7be 100644 --- a/configure.ac +++ b/configure.ac @@ -56,6 +56,7 @@ if test x$ac_cv_func_strsep != xyes; then fi fi +AC_SEARCH_LIBS([ceil], [m]) AC_CHECK_HEADER(endian.h, [ac_cv_have_endian_h="yes"], [ac_cv_have_endian_h="no"]) if test "x$ac_cv_have_endian_h" = "xno"; then