summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am7
-rw-r--r--src/ace3.c244
-rw-r--r--src/ace3.h17
-rw-r--r--src/asr.c70
-rw-r--r--src/asr.h9
-rw-r--r--src/common.c99
-rw-r--r--src/common.h18
-rw-r--r--src/dfu.c129
-rw-r--r--src/dfu.h9
-rw-r--r--src/fdr.c2
-rw-r--r--src/idevicerestore.c883
-rw-r--r--src/idevicerestore.h18
-rw-r--r--src/img4.c238
-rw-r--r--src/img4.h2
-rw-r--r--src/ipsw.c427
-rw-r--r--src/ipsw.h46
-rw-r--r--src/jsmn.c280
-rw-r--r--src/jsmn.h91
-rw-r--r--src/json_plist.c229
-rw-r--r--src/json_plist.h34
-rw-r--r--src/normal.c69
-rw-r--r--src/normal.h5
-rw-r--r--src/recovery.c44
-rw-r--r--src/recovery.h5
-rw-r--r--src/restore.c994
-rw-r--r--src/restore.h9
-rw-r--r--src/tss.c1133
-rw-r--r--src/tss.h5
28 files changed, 2708 insertions, 2408 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 4a99dec..722487a 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) \
@@ -42,12 +44,11 @@ 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 \
- locking.c locking.h \
- jsmn.c jsmn.h \
- json_plist.c json_plist.h
+ locking.c locking.h
if USE_INTERNAL_SHA
idevicerestore_SOURCES += sha1.c sha1.h sha512.c sha512.h fixedint.h
endif
diff --git a/src/ace3.c b/src/ace3.c
new file mode 100644
index 0000000..b96e6b4
--- /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 <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <libimobiledevice-glue/nskeyedarchive.h>
+
+#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 0000000..2ef65a7
--- /dev/null
+++ b/src/ace3.h
@@ -0,0 +1,17 @@
+#ifndef IDEVICERESTORE_ACE3_H
+#define IDEVICERESTORE_ACE3_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <plist/plist.h>
+
+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/asr.c b/src/asr.c
index a1aba76..bf15dc2 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,7 @@ 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
+ length = ipsw_file_size(file);
payload_info = plist_new_dict();
plist_dict_set_item(payload_info, "Port", plist_new_uint(1));
@@ -296,7 +283,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,14 +311,14 @@ 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) {
- 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;
}
@@ -345,28 +332,14 @@ 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
+ length = ipsw_file_size(file);
+ ipsw_file_seek(file, 0, SEEK_SET);
data = (char*)malloc(ASR_PAYLOAD_CHUNK_SIZE + 20);
@@ -376,26 +349,28 @@ int asr_send_payload(asr_client_t asr, const char* filesystem)
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;
}
- 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;
}
+ 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;
@@ -412,6 +387,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 b3336a5..0d9534c 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.c b/src/common.c
index 4dbabc0..e5ee07b 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;
@@ -467,7 +468,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);
}
}
@@ -557,91 +558,19 @@ 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)
+const char* path_get_basename(const char* path)
{
- uint64_t uintval = 0;
- char *strval = NULL;
- uint64_t strsz = 0;
- plist_t node = plist_dict_get_item(dict, key);
- if (!node) {
- return (uint64_t)-1LL;
- }
- 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);
+#ifdef WIN32
+ const char *p = path + strlen(path);
+ while (p > path) {
+ if ((*p == '/') || (*p == '\\')) {
+ return p+1;
}
- break;
- default:
- break;
+ p--;
}
- return bval;
+ return p;
+#else
+ const char *p = strrchr(path, '/');
+ return p ? p + 1 : path;
+#endif
}
diff --git a/src/common.h b/src/common.h
index 6c839ce..766a385 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
@@ -70,6 +72,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;
@@ -88,6 +93,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;
@@ -101,8 +107,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;
@@ -111,6 +116,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;
@@ -123,6 +130,10 @@ struct idevicerestore_client_t {
mutex_t device_event_mutex;
cond_t device_event_cond;
int ignore_device_add_events;
+ plist_t macos_variant;
+ char* restore_variant;
+ char* filesystem;
+ int delete_fs;
};
extern struct idevicerestore_mode_t idevicerestore_modes[];
@@ -180,8 +191,7 @@ 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);
+const char* path_get_basename(const char* path);
#ifdef __cplusplus
}
diff --git a/src/dfu.c b/src/dfu.c
index a675c53..cc8e1fb 100644
--- a/src/dfu.c
+++ b/src/dfu.c
@@ -42,8 +42,6 @@ static int dfu_progress_callback(irecv_client_t client, const irecv_event_t* eve
int dfu_client_new(struct idevicerestore_client_t* client)
{
- int i = 0;
- int attempts = 10;
irecv_client_t dfu = NULL;
if (client->dfu == NULL) {
@@ -55,18 +53,9 @@ int dfu_client_new(struct idevicerestore_client_t* client)
}
}
- for (i = 1; i <= attempts; i++) {
- if (irecv_open_with_ecid(&dfu, client->ecid) == IRECV_E_SUCCESS) {
- break;
- }
-
- if (i >= attempts) {
- error("ERROR: Unable to connect to device in DFU mode\n");
- return -1;
- }
-
- sleep(1);
- debug("Retrying connection...\n");
+ if (irecv_open_with_ecid_and_attempts(&dfu, client->ecid, 10) != IRECV_E_SUCCESS) {
+ error("ERROR: Unable to connect to device in DFU mode\n");
+ return -1;
}
irecv_event_subscribe(dfu, IRECV_PROGRESS, &dfu_progress_callback, NULL);
@@ -95,11 +84,17 @@ irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client)
irecv_device_t device = NULL;
irecv_init();
- if (irecv_open_with_ecid(&dfu, client->ecid) != IRECV_E_SUCCESS) {
+ if (irecv_open_with_ecid_and_attempts(&dfu, client->ecid, 10) != IRECV_E_SUCCESS) {
return NULL;
}
dfu_error = irecv_devices_get_device_by_client(dfu, &device);
+ if (dfu_error == IRECV_E_SUCCESS) {
+ if (client->ecid == 0) {
+ const struct irecv_device_info *device_info = irecv_get_device_info(dfu);
+ client->ecid = device_info->ecid;
+ }
+ }
irecv_close(dfu);
if (dfu_error != IRECV_E_SUCCESS) {
return NULL;
@@ -108,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;
@@ -123,6 +118,11 @@ int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffe
return 0;
}
+int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size)
+{
+ 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)
{
char* path = NULL;
@@ -198,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);
@@ -209,7 +209,7 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide
return 0;
}
-int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid)
+int dfu_get_bdid(struct idevicerestore_client_t* client, unsigned int* bdid)
{
if(client->dfu == NULL) {
if (dfu_client_new(client) < 0) {
@@ -222,12 +222,12 @@ int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid)
return -1;
}
- *cpid = device_info->cpid;
+ *bdid = device_info->bdid;
return 0;
}
-int dfu_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid)
+int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid)
{
if(client->dfu == NULL) {
if (dfu_client_new(client) < 0) {
@@ -240,11 +240,32 @@ int dfu_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid)
return -1;
}
- *ecid = device_info->ecid;
+ *cpid = device_info->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) {
@@ -261,7 +282,36 @@ 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_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) {
if (dfu_client_new(client) < 0) {
@@ -286,7 +336,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) {
@@ -372,11 +422,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);
@@ -438,7 +490,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");
@@ -484,7 +536,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide
mutex_lock(&client->device_event_mutex);
// Now, before sending iBEC, we must send necessary firmwares on new versions.
- if (client->build_major >= 20) {
+ if (client->macos_variant) {
// Without this empty policy file & its special signature, iBEC won't start.
if (dfu_send_component_and_command(client, build_identity, "Ap,LocalPolicy", "lpolrestore") < 0) {
mutex_unlock(&client->device_event_mutex);
@@ -494,6 +546,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/dfu.h b/src/dfu.h
index f501531..4590dbd 100644
--- a/src/dfu.h
+++ b/src/dfu.h
@@ -41,12 +41,15 @@ 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_ecid(struct idevicerestore_client_t* client, uint64_t* ecid);
+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_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_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/fdr.c b/src/fdr.c
index e3703fe..ca9b7c7 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) {
diff --git a/src/idevicerestore.c b/src/idevicerestore.c
index 017b45c..f27c357 100644
--- a/src/idevicerestore.c
+++ b/src/idevicerestore.c
@@ -45,6 +45,9 @@
#define SHA384 sha384
#endif
+#include <libimobiledevice-glue/utils.h>
+
+#include "ace3.h"
#include "dfu.h"
#include "tss.h"
#include "img3.h"
@@ -72,7 +75,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' },
@@ -87,6 +90,7 @@ static struct option longopts[] = {
{ "version", no_argument, NULL, 'v' },
{ "ipsw-info", no_argument, NULL, 'I' },
{ "ignore-errors", no_argument, NULL, 1 },
+ { "variant", required_argument, NULL, 2 },
{ NULL, 0, NULL, 0 }
};
@@ -131,8 +135,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" \
@@ -140,6 +144,8 @@ static void usage(int argc, char* argv[], int err)
" -P, --plain-progress Print progress as plain step and progress\n" \
" -R, --restore-mode Allow restoring from Restore mode\n" \
" -T, --ticket PATH Use file at PATH to send as AP ticket\n" \
+ " --variant VARIANT Use given VARIANT to match the build identity to use,\n" \
+ " e.g. 'Customer Erase Install (IPSW)'\n" \
" --ignore-errors Try to continue the restore process after certain\n" \
" errors (like a failed baseband update)\n" \
" WARNING: This might render the device unable to boot\n" \
@@ -293,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:
@@ -311,12 +320,20 @@ 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);
}
}
}
+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;
@@ -336,10 +353,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);
@@ -421,7 +440,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");
}
@@ -453,6 +474,12 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
error("ERROR: Unable to discover device type\n");
return -1;
}
+ if (client->ecid == 0) {
+ error("ERROR: Unable to determine ECID\n");
+ return -1;
+ }
+ info("ECID: %" PRIu64 "\n", client->ecid);
+
idevicerestore_progress(client, RESTORE_STEP_DETECT, 0.2);
info("Identified device as %s, %s\n", client->device->hardware_model, client->device->product_type);
@@ -461,6 +488,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);
@@ -473,17 +515,24 @@ 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");
+
+ 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");
+ 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) {
@@ -585,12 +634,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);
@@ -599,14 +652,29 @@ 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->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;
@@ -625,26 +693,152 @@ 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;
- }
+ if (client->mode == MODE_PORTDFU) {
+ unsigned int pdfu_bdid = 0;
+ unsigned int pdfu_cpid = 0;
+ unsigned int prev = 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);
+ if (dfu_get_bdid(client, &pdfu_bdid) < 0) {
+ error("ERROR: Failed to get bdid for Port DFU device!\n");
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);
+ 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 */
@@ -656,23 +850,19 @@ 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");
- 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;
+ int build_identity_needs_free = 0;
if (client->flags & FLAG_CUSTOM) {
build_identity = plist_new_dict();
+ build_identity_needs_free = 1;
{
plist_t node;
plist_t comp;
@@ -699,6 +889,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
uint32_t msize = 0;
if (ipsw_extract_to_memory(client->ipsw, tmpstr, (unsigned char**)&fmanifest, &msize) < 0) {
error("ERROR: could not extract %s from IPSW\n", tmpstr);
+ free(build_identity);
return -1;
}
@@ -816,40 +1007,42 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
// add info
inf = plist_new_dict();
plist_dict_set_item(inf, "RestoreBehavior", plist_new_string((client->flags & FLAG_ERASE) ? "Erase" : "Update"));
- plist_dict_set_item(inf, "Variant", plist_new_string((client->flags & FLAG_ERASE) ? "Customer Erase Install (IPSW)" : "Customer Upgrade Install (IPSW)"));
+ plist_dict_set_item(inf, "Variant", plist_new_string((client->flags & FLAG_ERASE) ? "Customer " RESTORE_VARIANT_ERASE_INSTALL : "Customer " RESTORE_VARIANT_UPGRADE_INSTALL));
plist_dict_set_item(build_identity, "Info", inf);
// finally add manifest
plist_dict_set_item(build_identity, "Manifest", manifest);
}
+ } else if (client->restore_variant) {
+ build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, client->restore_variant, 1);
} else if (client->flags & FLAG_ERASE) {
- build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, "Customer Erase Install (IPSW)");
- if (build_identity == NULL) {
- error("ERROR: Unable to find any build identities\n");
- return -1;
- }
+ build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_ERASE_INSTALL, 0);
} else {
- build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, "Customer Upgrade Install (IPSW)");
+ build_identity = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_UPGRADE_INSTALL, 0);
if (!build_identity) {
build_identity = build_manifest_get_build_identity_for_model(client->build_manifest, client->device->hardware_model);
}
}
+ if (build_identity == NULL) {
+ error("ERROR: Unable to find a matching build identity\n");
+ return -1;
+ }
+
+ client->macos_variant = build_manifest_get_build_identity_for_model_with_variant(client->build_manifest, client->device->hardware_model, RESTORE_VARIANT_MACOS_RECOVERY_OS, 1);
/* print information about current build identity */
build_identity_print_information(build_identity);
+ if (client->macos_variant) {
+ info("Performing macOS restore\n");
+ }
+
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"
@@ -860,7 +1053,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);
@@ -879,7 +1072,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
}
}
}
- free(device_version);
}
if (client->flags & FLAG_ERASE && client->flags & FLAG_INTERACTIVE) {
@@ -914,112 +1106,74 @@ 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) {
+ /* 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 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);
+ /* 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);
}
- 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 == '.') {
+ 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 = strdup(path_get_basename(client->ipsw->path));
+ char* p = strrchr(ipsw_basename, '.');
+ if (p && isalpha(*(p+1))) {
*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;
+ 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 {
- // use <fsname>.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;
+ tmpf = get_temp_filename(NULL);
+ client->delete_fs = 1;
}
- if (strstr(filesystem, ".extract")) {
- // rename <fsname>.extract to <fsname>
- remove(tmpf);
- rename(filesystem, tmpf);
- free(filesystem);
- filesystem = strdup(tmpf);
+ /* 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;
}
}
@@ -1028,13 +1182,6 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
/* retrieve shsh blobs if required */
if (tss_enabled) {
int stashbag_commit_required = 0;
- debug("Getting device's ECID for TSS request\n");
- /* fetch the device's ECID for the TSS request */
- if (get_ecid(client, &client->ecid) < 0) {
- error("ERROR: Unable to find device ECID\n");
- return -1;
- }
- info("Found ECID %" PRIu64 "\n", client->ecid);
if (client->mode == MODE_NORMAL && !(client->flags & FLAG_ERASE) && !(client->flags & FLAG_SHSHONLY)) {
plist_t node = normal_get_lockdown_value(client, NULL, "HasSiDP");
@@ -1067,7 +1214,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");
@@ -1088,20 +1235,33 @@ 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->build_major >= 20) {
- 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((char*)client->root_ticket, client->root_ticket_len);
+ if (!ap_ticket) {
+ error("ERROR: Failed to create ApImg4Ticket node value.\n");
+ return -1;
+ }
+ client->tss = plist_new_dict();
+ if (!client->tss) {
+ error("ERROR: Failed to create ApImg4Ticket node.\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");
+ 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) {
@@ -1120,8 +1280,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) {
@@ -1176,8 +1334,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;
}
@@ -1194,8 +1350,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;
}
@@ -1206,17 +1360,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");
- // 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);
- if (delete_fs && filesystem)
- unlink(filesystem);
return -1;
}
dfu_client_free(client);
@@ -1226,8 +1375,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) {
@@ -1237,8 +1384,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;
}
}
@@ -1250,54 +1395,44 @@ 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);
debug("Waiting for device to disconnect...\n");
- cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
+ cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000);
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. 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");
- cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 10000);
+ cond_wait_timeout(&client->device_event_cond, &client->device_event_mutex, 60000);
if (client->mode != MODE_RECOVERY || (client->flags & FLAG_QUIT)) {
mutex_unlock(&client->device_event_mutex);
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;
}
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");
recovery_send_reset(client);
- if (delete_fs && filesystem)
- unlink(filesystem);
return -2;
}
@@ -1317,14 +1452,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);
@@ -1332,25 +1463,15 @@ 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;
}
// now finally do the magic to put the device into restore mode
if (client->mode == MODE_RECOVERY) {
- if (client->srnm == NULL) {
- error("ERROR: could not retrieve device serial number. Can't continue.\n");
- if (delete_fs && filesystem)
- unlink(filesystem);
- return -1;
- }
if (recovery_enter_restore(client, build_identity) < 0) {
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);
@@ -1365,8 +1486,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);
@@ -1380,19 +1499,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) {
@@ -1412,7 +1525,7 @@ int idevicerestore_start(struct idevicerestore_client_t* client)
idevicerestore_progress(client, RESTORE_NUM_STEPS-1, 1.0);
}
- if (build_identity)
+ if (build_identity_needs_free)
plist_free(build_identity);
return result;
@@ -1463,14 +1576,18 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client)
free(client->srnm);
}
if (client->ipsw) {
- free(client->ipsw);
- }
- if (client->version) {
- free(client->version);
+ ipsw_close(client->ipsw);
}
- if (client->build) {
- free(client->build);
+ if (client->filesystem) {
+ if (client->delete_fs) {
+ unlink(client->filesystem);
+ }
+ free(client->filesystem);
}
+ free(client->version);
+ free(client->build);
+ free(client->device_version);
+ free(client->device_build);
if (client->restore_boot_args) {
free(client->restore_boot_args);
}
@@ -1486,6 +1603,7 @@ void idevicerestore_client_free(struct idevicerestore_client_t* client)
if (client->preflight_info) {
plist_free(client->preflight_info);
}
+ free(client->restore_variant);
free(client);
}
@@ -1521,11 +1639,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);
}
}
@@ -1603,7 +1721,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);
@@ -1611,6 +1729,7 @@ int main(int argc, char* argv[]) {
case 'd':
client->flags |= FLAG_DEBUG;
+ client->debug_level++;
break;
case 'e':
@@ -1621,8 +1740,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':
@@ -1716,6 +1862,11 @@ int main(int argc, char* argv[]) {
client->flags |= FLAG_IGNORE_ERRORS;
break;
+ case 2:
+ free(client->restore_variant);
+ client->restore_variant = strdup(optarg);
+ break;
+
default:
usage(argc, argv, 1);
return EXIT_FAILURE;
@@ -1746,8 +1897,15 @@ int main(int argc, char* argv[]) {
return EXIT_FAILURE;
}
+ 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);
@@ -1778,6 +1936,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);
@@ -1815,46 +1974,7 @@ int is_image4_supported(struct idevicerestore_client_t* client)
return res;
}
-int get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid)
-{
- int mode = _MODE_UNKNOWN;
-
- if (client->mode) {
- mode = client->mode->index;
- }
-
- switch (mode) {
- case _MODE_NORMAL:
- if (normal_get_ecid(client, ecid) < 0) {
- *ecid = 0;
- return -1;
- }
- break;
-
- case _MODE_DFU:
- if (dfu_get_ecid(client, ecid) < 0) {
- *ecid = 0;
- return -1;
- }
- break;
-
- case _MODE_RECOVERY:
- if (recovery_get_ecid(client, ecid) < 0) {
- *ecid = 0;
- return -1;
- }
- break;
-
- default:
- error("ERROR: Device is in an invalid state\n");
- *ecid = 0;
- return -1;
- }
-
- return 0;
-}
-
-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;
@@ -1905,7 +2025,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;
@@ -1956,7 +2076,7 @@ int get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce,
return 0;
}
-plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_manifest, const char *hardware_model, const char *variant)
+plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_manifest, const char *hardware_model, const char *variant, int exact)
{
plist_t build_identities_array = plist_dict_get_item(build_manifest, "BuildIdentities");
if (!build_identities_array || plist_get_node_type(build_identities_array) != PLIST_ARRAY) {
@@ -1978,30 +2098,27 @@ plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_m
if (!devclass || plist_get_node_type(devclass) != PLIST_STRING) {
continue;
}
- char *str = NULL;
- plist_get_string_val(devclass, &str);
+ const char *str = plist_get_string_ptr(devclass, NULL);
if (strcasecmp(str, hardware_model) != 0) {
- free(str);
continue;
}
- free(str);
- str = NULL;
if (variant) {
plist_t rvariant = plist_dict_get_item(info_dict, "Variant");
if (!rvariant || plist_get_node_type(rvariant) != PLIST_STRING) {
continue;
}
- plist_get_string_val(rvariant, &str);
- if (strcasecmp(str, variant) != 0) {
- free(str);
+ str = plist_get_string_ptr(rvariant, NULL);
+ if (strcmp(str, variant) != 0) {
+ /* if it's not a full match, let's try a partial match, but ignore "*Research*" */
+ if (!exact && strstr(str, variant) && !strstr(str, "Research")) {
+ return ident;
+ }
continue;
} else {
- free(str);
- return plist_copy(ident);
+ return ident;
}
- free(str);
} else {
- return plist_copy(ident);
+ return ident;
}
}
@@ -2010,7 +2127,7 @@ plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_m
plist_t build_manifest_get_build_identity_for_model(plist_t build_manifest, const char *hardware_model)
{
- return build_manifest_get_build_identity_for_model_with_variant(build_manifest, hardware_model, NULL);
+ return build_manifest_get_build_identity_for_model_with_variant(build_manifest, hardware_model, NULL, 0);
}
int get_preboard_manifest(struct idevicerestore_client_t* client, plist_t build_identity, plist_t* manifest)
@@ -2028,13 +2145,13 @@ 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));
plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(1));
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
/* create basic request */
request = tss_request_new(NULL);
@@ -2052,7 +2169,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) {
@@ -2149,7 +2266,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) {
@@ -2165,7 +2282,7 @@ int get_tss_response(struct idevicerestore_client_t* client, plist_t build_ident
plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0));
}
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
/* create basic request */
request = tss_request_new(NULL);
@@ -2214,50 +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_t node;
- node = plist_dict_get_item(pinfo, "Nonce");
- if (node) {
- plist_dict_set_item(parameters, "BbNonce", plist_copy(node));
- }
- node = plist_dict_get_item(pinfo, "ChipID");
- if (node) {
- plist_dict_set_item(parameters, "BbChipID", plist_copy(node));
- }
- node = plist_dict_get_item(pinfo, "CertID");
- if (node) {
- plist_dict_set_item(parameters, "BbGoldCertId", plist_copy(node));
- }
- node = plist_dict_get_item(pinfo, "ChipSerialNo");
- if (node) {
- plist_dict_set_item(parameters, "BbSNUM", plist_copy(node));
- }
+ 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);
- node = plist_dict_get_item(pinfo, "EUICCChipID");
- uint64_t euiccchipid = 0;
- if (node && plist_get_node_type(node) == PLIST_UINT) {
- plist_get_uint_val(node, &euiccchipid);
- plist_dict_set_item(parameters, "eUICC,ChipID", plist_copy(node));
- }
- if (euiccchipid >= 5) {
- node = plist_dict_get_item(pinfo, "EUICCCSN");
- if (node) {
- plist_dict_set_item(parameters, "eUICC,EID", plist_copy(node));
- }
- node = plist_dict_get_item(pinfo, "EUICCCertIdentifier");
- if (node) {
- plist_dict_set_item(parameters, "eUICC,RootKeyIdentifier", plist_copy(node));
- }
- node = plist_dict_get_item(pinfo, "EUICCGoldNonce");
- if (node) {
- plist_dict_set_item(parameters, "EUICCGoldNonce", plist_copy(node));
- }
- node = plist_dict_get_item(pinfo, "EUICCMainNonce");
- if (node) {
- plist_dict_set_item(parameters, "EUICCMainNonce", plist_copy(node));
- }
+ 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);
@@ -2303,7 +2390,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 */
@@ -2323,10 +2410,10 @@ int get_recoveryos_root_ticket_tss_response(struct idevicerestore_client_t* clie
plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0));
}
- tss_parameters_add_from_manifest(parameters, build_identity);
+ 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");
@@ -2335,7 +2422,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);
@@ -2403,7 +2490,7 @@ int get_recovery_os_local_policy_tss_response(
plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0));
}
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
// Add Ap,LocalPolicy
uint8_t digest[SHA384_DIGEST_LENGTH];
@@ -2413,11 +2500,8 @@ int get_recovery_os_local_policy_tss_response(
plist_dict_set_item(lpol, "Trusted", plist_new_bool(1));
plist_dict_set_item(parameters, "Ap,LocalPolicy", lpol);
- plist_t im4m_hash = plist_dict_get_item(args, "Ap,NextStageIM4MHash");
- plist_dict_set_item(parameters, "Ap,NextStageIM4MHash", plist_copy(im4m_hash));
-
- plist_t nonce_hash = plist_dict_get_item(args, "Ap,RecoveryOSPolicyNonceHash");
- plist_dict_set_item(parameters, "Ap,RecoveryOSPolicyNonceHash", plist_copy(nonce_hash));
+ 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;
@@ -2485,7 +2569,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) {
@@ -2501,7 +2585,7 @@ int get_local_policy_tss_response(struct idevicerestore_client_t* client, plist_
plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0));
}
- tss_parameters_add_from_manifest(parameters, build_identity);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
// Add Ap,LocalPolicy
uint8_t digest[SHA384_DIGEST_LENGTH];
@@ -2594,12 +2678,10 @@ int build_manifest_get_identity_count(plist_t build_manifest)
error("ERROR: Unable to find build identities node\n");
return -1;
}
-
- // check and make sure this identity exists in buildmanifest
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) {
@@ -2614,7 +2696,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;
}
@@ -2628,9 +2710,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) {
@@ -2733,20 +2815,13 @@ void build_identity_print_information(plist_t build_identity)
plist_get_string_val(node, &value);
info("Variant: %s\n", value);
- free(value);
-
- node = plist_dict_get_item(info_node, "RestoreBehavior");
- if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to find RestoreBehavior node\n");
- return;
- }
- plist_get_string_val(node, &value);
-
- if (!strcmp(value, "Erase"))
- info("This restore will erase your device data.\n");
- if (!strcmp(value, "Update"))
- info("This restore will update your device without erasing user data.\n");
+ if (strstr(value, RESTORE_VARIANT_UPGRADE_INSTALL))
+ info("This restore will update the device without erasing user data.\n");
+ else if (strstr(value, RESTORE_VARIANT_ERASE_INSTALL))
+ info("This restore will erase all device data.\n");
+ else
+ info("Unknown Variant '%s'\n", value);
free(value);
@@ -2754,7 +2829,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) {
@@ -2846,42 +2921,38 @@ int build_identity_get_component_path(plist_t build_identity, const char* compon
const char* get_component_name(const char* filename)
{
- if (!strncmp(filename, "LLB", 3)) {
- return "LLB";
- } else if (!strncmp(filename, "iBoot", 5)) {
- return "iBoot";
- } else if (!strncmp(filename, "DeviceTree", 10)) {
- return "DeviceTree";
- } else if (!strncmp(filename, "applelogo", 9)) {
- return "AppleLogo";
- } else if (!strncmp(filename, "liquiddetect", 12)) {
- return "Liquid";
- } else if (!strncmp(filename, "lowpowermode", 12)) {
- return "LowPowerWallet0";
- } else if (!strncmp(filename, "recoverymode", 12)) {
- return "RecoveryMode";
- } else if (!strncmp(filename, "batterylow0", 11)) {
- return "BatteryLow0";
- } else if (!strncmp(filename, "batterylow1", 11)) {
- return "BatteryLow1";
- } else if (!strncmp(filename, "glyphcharging", 13)) {
- return "BatteryCharging";
- } else if (!strncmp(filename, "glyphplugin", 11)) {
- return "BatteryPlugin";
- } else if (!strncmp(filename, "batterycharging0", 16)) {
- return "BatteryCharging0";
- } else if (!strncmp(filename, "batterycharging1", 16)) {
- return "BatteryCharging1";
- } else if (!strncmp(filename, "batteryfull", 11)) {
- return "BatteryFull";
- } else if (!strncmp(filename, "needservice", 11)) {
- return "NeedService";
- } else if (!strncmp(filename, "SCAB", 4)) {
- return "SCAB";
- } else if (!strncmp(filename, "sep-firmware", 12)) {
- return "RestoreSEP";
- } else {
- error("WARNING: Unhandled component '%s'", filename);
- return NULL;
+ struct filename_component_map {
+ const char *fnprefix;
+ int matchlen;
+ const char *compname;
+ };
+ struct filename_component_map fn_comp_map[] = {
+ { "LLB", 3, "LLB" },
+ { "iBoot", 5, "iBoot" },
+ { "DeviceTree", 10, "DeviceTree" },
+ { "applelogo", 9, "AppleLogo" },
+ { "liquiddetect", 12, "Liquid" },
+ { "lowpowermode", 12, "LowPowerWallet0" },
+ { "recoverymode", 12, "RecoveryMode" },
+ { "batterylow0", 11, "BatteryLow0" },
+ { "batterylow1", 11, "BatteryLow1" },
+ { "glyphcharging", 13, "BatteryCharging" },
+ { "glyphplugin", 11, "BatteryPlugin" },
+ { "batterycharging0", 16, "BatteryCharging0" },
+ { "batterycharging1", 16, "BatteryCharging1" },
+ { "batteryfull", 11, "BatteryFull" },
+ { "needservice", 11, "NeedService" },
+ { "SCAB", 4, "SCAB" },
+ { "sep-firmware", 12, "RestoreSEP" },
+ { NULL, 0, NULL }
+ };
+ int i = 0;
+ while (fn_comp_map[i].fnprefix) {
+ if (!strncmp(filename, fn_comp_map[i].fnprefix, fn_comp_map[i].matchlen)) {
+ return fn_comp_map[i].compname;
+ }
+ i++;
}
+ error("WARNING: Unhandled component '%s'", filename);
+ return NULL;
}
diff --git a/src/idevicerestore.h b/src/idevicerestore.h
index 880f9ee..5afcf1a 100644
--- a/src/idevicerestore.h
+++ b/src/idevicerestore.h
@@ -47,7 +47,13 @@ extern "C" {
#define FLAG_NO_RESTORE (1 << 11)
#define FLAG_IGNORE_ERRORS (1 << 12)
+#define RESTORE_VARIANT_ERASE_INSTALL "Erase Install (IPSW)"
+#define RESTORE_VARIANT_UPGRADE_INSTALL "Upgrade Install (IPSW)"
+#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,
@@ -57,6 +63,7 @@ enum {
RESTORE_STEP_FLASH_FW,
RESTORE_STEP_FLASH_BB,
RESTORE_STEP_FUD,
+ RESTORE_STEP_UPLOAD_IMG,
RESTORE_NUM_STEPS
};
@@ -86,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);
@@ -101,14 +108,13 @@ int build_manifest_get_identity_count(plist_t build_manifest);
int build_manifest_check_compatibility(plist_t build_manifest, const char* product);
void build_manifest_get_version_information(plist_t build_manifest, struct idevicerestore_client_t* client);
plist_t build_manifest_get_build_identity_for_model(plist_t build_manifest, const char *hardware_model);
-plist_t build_manifest_get_build_identity_for_model_with_variant(plist_t build_manifest, const char *hardware_model, const char *variant);
+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/img4.c b/src/img4.c
index 4988293..9a0cb29 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;
}
}
@@ -275,28 +276,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 +315,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 +341,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 +358,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 +370,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;
@@ -381,7 +394,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, 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)
{
unsigned char* magic_header = NULL;
unsigned int magic_header_size = 0;
@@ -392,8 +405,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 || !tss_response || !img4_data || !img4_size) {
+ return -1;
+ }
- if (!component_name || !component_data || component_size == 0 || !blob || blob_size == 0 || !img4_data || !img4_size) {
+ 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;
}
@@ -423,13 +443,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);
@@ -445,6 +604,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;
}
@@ -463,6 +623,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);
@@ -476,6 +640,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo
if (img4header) {
free(img4header);
}
+ free(additional_data);
return 0;
}
@@ -540,13 +705,11 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c
node = plist_dict_get_item(comp, "Digest");
if (node) {
- char *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");
@@ -575,9 +738,8 @@ static void _manifest_write_component(unsigned char **p, unsigned int *length, c
node = plist_dict_get_item(comp, "TBMDigests");
if (node) {
- char *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";
@@ -587,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);
@@ -627,30 +788,28 @@ int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t*
unsigned int length = 0;
uint64_t uintval = 0;
unsigned int boolval = 0;
- char *strval = NULL;
- plist_t node = NULL;
unsigned char tmp_[1024];
unsigned char *tmp = &tmp_[0];
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 */
@@ -681,13 +840,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/img4.h b/src/img4.h
index 37dea56..1056fa6 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
diff --git a/src/ipsw.c b/src/ipsw.c
index da00a6e..c25f61d 100644
--- a/src/ipsw.c
+++ b/src/ipsw.c
@@ -45,26 +45,18 @@
#endif
#include <libimobiledevice-glue/termcolors.h>
+#include <plist/plist.h>
#include "ipsw.h"
#include "locking.h"
#include "download.h"
#include "common.h"
#include "idevicerestore.h"
-#include "json_plist.h"
#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;
@@ -134,7 +129,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;
@@ -152,10 +147,10 @@ int ipsw_print_info(const char* path)
plist_get_string_val(val, &build_ver);
}
- cprintf(COLOR_WHITE "Product Version: " COLOR_BRIGHT_YELLOW "%s" COLOR_RESET COLOR_WHITE " Build: " COLOR_BRIGHT_YELLOW "%s" COLOR_RESET "\n", prod_ver, build_ver);
+ cprintf(FG_WHITE "Product Version: " FG_BRIGHT_YELLOW "%s" COLOR_RESET FG_WHITE " Build: " FG_BRIGHT_YELLOW "%s" COLOR_RESET "\n", prod_ver, build_ver);
free(prod_ver);
free(build_ver);
- cprintf(COLOR_WHITE "Supported Product Types:" COLOR_RESET);
+ cprintf(FG_WHITE "Supported Product Types:" COLOR_RESET);
val = plist_dict_get_item(manifest, "SupportedProductTypes");
if (val) {
plist_array_iter iter = NULL;
@@ -167,7 +162,7 @@ int ipsw_print_info(const char* path)
if (item) {
char* item_str = NULL;
plist_get_string_val(item, &item_str);
- cprintf(" " COLOR_BRIGHT_CYAN "%s" COLOR_RESET, item_str);
+ cprintf(" " FG_BRIGHT_CYAN "%s" COLOR_RESET, item_str);
free(item_str);
}
} while (item);
@@ -176,7 +171,7 @@ int ipsw_print_info(const char* path)
}
cprintf("\n");
- cprintf(COLOR_WHITE "Build Identities:" COLOR_RESET "\n");
+ cprintf(FG_WHITE "Build Identities:" COLOR_RESET "\n");
plist_t build_ids_grouped = plist_new_dict();
@@ -201,7 +196,15 @@ int ipsw_print_info(const char* path)
if (!group) {
group = plist_new_dict();
node = plist_access_path(build_identity, 2, "Info", "RestoreBehavior");
- plist_dict_set_item(group, "RestoreBehavior", plist_copy(node));
+ if (node) {
+ plist_dict_set_item(group, "RestoreBehavior", plist_copy(node));
+ } else {
+ if (strstr(variant_str, "Upgrade")) {
+ plist_dict_set_item(group, "RestoreBehavior", plist_new_string("Update"));
+ } else if (strstr(variant_str, "Erase")) {
+ plist_dict_set_item(group, "RestoreBehavior", plist_new_string("Erase"));
+ }
+ }
entries = plist_new_array();
plist_dict_set_item(group, "Entries", entries);
plist_dict_set_item(build_ids_grouped, variant_str, group);
@@ -232,7 +235,7 @@ int ipsw_print_info(const char* path)
group_no++;
node = plist_dict_get_item(group, "RestoreBehavior");
plist_get_string_val(node, &rbehavior);
- cprintf(" " COLOR_WHITE "[%d] Variant: " COLOR_BRIGHT_CYAN "%s" COLOR_WHITE " Behavior: " COLOR_BRIGHT_CYAN "%s" COLOR_RESET "\n", group_no, key, rbehavior);
+ cprintf(" " FG_WHITE "[%d] Variant: " FG_BRIGHT_CYAN "%s" FG_WHITE " Behavior: " FG_BRIGHT_CYAN "%s" COLOR_RESET "\n", group_no, key, rbehavior);
free(key);
free(rbehavior);
@@ -285,9 +288,9 @@ int ipsw_print_info(const char* path)
irecv_device_t irecvdev = NULL;
if (irecv_devices_get_device_by_hardware_model(hwmodel, &irecvdev) == 0) {
- cprintf(" ChipID: " COLOR_GREEN "%04x" COLOR_RESET " BoardID: " COLOR_GREEN "%02x" COLOR_RESET " Model: " COLOR_YELLOW "%-8s" COLOR_RESET " " COLOR_MAGENTA "%s" COLOR_RESET "\n", (int)chip_id, (int)board_id, hwmodel, irecvdev->display_name);
+ cprintf(" ChipID: " FG_GREEN "%04x" COLOR_RESET " BoardID: " FG_GREEN "%02x" COLOR_RESET " Model: " FG_YELLOW "%-8s" COLOR_RESET " " FG_MAGENTA "%s" COLOR_RESET "\n", (int)chip_id, (int)board_id, hwmodel, irecvdev->display_name);
} else {
- cprintf(" ChipID: " COLOR_GREEN "%04x" COLOR_RESET " BoardID: " COLOR_GREEN "%02x" COLOR_RESET " Model: " COLOR_YELLOW "%s" COLOR_RESET "\n", (int)chip_id, (int)board_id, hwmodel);
+ cprintf(" ChipID: " FG_GREEN "%04x" COLOR_RESET " BoardID: " FG_GREEN "%02x" COLOR_RESET " Model: " FG_YELLOW "%s" COLOR_RESET "\n", (int)chip_id, (int)board_id, hwmodel);
}
free(hwmodel);
} while (build_id);
@@ -302,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;
@@ -316,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 {
@@ -327,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)
@@ -340,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);
@@ -378,23 +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 = ipsw_open(ipsw);
- if (archive == NULL) {
- error("ERROR: Invalid archive\n");
+
+ if (!ipsw || !infile || !outfile) {
+ error("ERROR: Invalid argument\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;
@@ -402,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;
}
@@ -413,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;
@@ -442,7 +452,7 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con
break;
}
if (fwrite(buffer, 1, count, fd) != count) {
- error("ERROR: frite: %s\n", outfile);
+ error("ERROR: Writing to '%s' failed: %s\n", outfile, strerror(errno));
ret = -1;
break;
}
@@ -457,9 +467,13 @@ 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) {
+ ret = -1;
+ goto leave;
+ }
if (!realpath(filepath, actual_filepath)) {
error("ERROR: realpath failed on %s: %s\n", filepath, strerror(errno));
ret = -1;
@@ -515,7 +529,7 @@ int ipsw_extract_to_file_with_progress(const char* ipsw, const char* infile, con
break;
}
if (fwrite(buffer, 1, r, fo) != r) {
- error("ERROR: fwrite failed\n");
+ error("ERROR: Writing to '%s' failed: %s\n", actual_outfile, strerror(errno));
ret = -1;
break;
}
@@ -534,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;
}
@@ -612,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;
}
@@ -620,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;
}
@@ -628,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) {
@@ -637,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;
@@ -645,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;
}
@@ -655,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 {
@@ -665,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) {
@@ -673,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);
@@ -684,14 +681,143 @@ 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_build_manifest(const char* ipsw, plist_t* buildmanifest, int *tss_enabled)
+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;
+
+ if (ipsw == NULL) {
+ error("ERROR: Invalid archive\n");
+ return -1;
+ }
+
+ 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);
+ return -1;
+ }
+
+ struct zip_stat zstat;
+ zip_stat_init(&zstat);
+ if (zip_stat_index(ipsw->zip, zindex, 0, &zstat) != 0) {
+ error("ERROR: zip_stat_index: %s\n", infile);
+ return -1;
+ }
+
+ struct zip_file* zfile = zip_fopen_index(ipsw->zip, zindex, 0);
+ if (zfile == NULL) {
+ error("ERROR: zip_fopen_index: %s\n", infile);
+ return -1;
+ }
+
+ total_size = zstat.size;
+ buffer = (unsigned char*) malloc(blocksize);
+ if (buffer == NULL) {
+ error("ERROR: Out of memory\n");
+ zip_fclose(zfile);
+ 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, done, total_size) < 0) {
+ error("ERROR: %s: send failed\n", __func__);
+ break;
+ }
+ done += zr;
+ }
+ free(buffer);
+ } else {
+ char *filepath = build_path(ipsw->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);
+ return -1;
+ }
+ total_size = fst.st_size;
+ buffer = (unsigned char*)malloc(blocksize);
+ if (buffer == NULL) {
+ error("ERROR: Out of memory\n");
+ free(filepath);
+ 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);
+ return -1;
+ }
+ send_callback(ctx, buffer, (size_t)rl, 0, 0);
+ } 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);
+ 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, done, total_size) < 0) {
+ error("ERROR: %s: send failed\n", __func__);
+ break;
+ }
+ done += fr;
+ }
+ fclose(f);
+#ifndef WIN32
+ }
+#endif
+ free(filepath);
+ free(buffer);
+ }
+
+ 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, done, total_size);
+
+ return 0;
+}
+
+int ipsw_extract_build_manifest(ipsw_archive_t ipsw, plist_t* buildmanifest, int *tss_enabled)
{
unsigned int size = 0;
unsigned char* data = NULL;
@@ -721,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;
@@ -735,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);
@@ -776,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);
@@ -790,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;
}
@@ -812,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;
@@ -820,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;
@@ -850,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];
@@ -892,7 +1003,7 @@ int ipsw_get_signed_firmwares(const char* product, plist_t* firmwares)
error("ERROR: Download from %s failed.\n", url);
return -1;
}
- dict = json_to_plist(jdata);
+ plist_from_json(jdata, jsize, &dict);
free(jdata);
if (!dict || plist_get_node_type(dict) != PLIST_DICT) {
error("ERROR: Failed to parse json data.\n");
@@ -1192,3 +1303,107 @@ 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) {
+ 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);
+ 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;
+ }
+ 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);
+ if (!handle->file) {
+ error("ERROR: fopen: %s could not be opened\n", path);
+ free(handle);
+ return NULL;
+ }
+ fstat(fileno(handle->file), &st);
+ handle->size = st.st_size;
+ handle->seekable = 1;
+ }
+ 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);
+}
+
+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) {
+ 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 3b5da80..f0e11a1 100644
--- a/src/ipsw.h
+++ b/src/ipsw.h
@@ -32,19 +32,47 @@ extern "C" {
#include <plist/plist.h>
#include <sys/stat.h>
+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, size_t done, size_t total_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);
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_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/jsmn.c b/src/jsmn.c
deleted file mode 100644
index a56f20a..0000000
--- a/src/jsmn.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * jsmn.c
- * Simple JSON parser
- *
- * Copyright (c) 2010 Serge A. Zaitsev
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include <stdlib.h>
-
-#include "jsmn.h"
-
-/**
- * Allocates a fresh unused token from the token pull.
- */
-static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
- jsmntok_t *tokens, size_t num_tokens) {
- jsmntok_t *tok;
- if (parser->toknext >= num_tokens) {
- return NULL;
- }
- tok = &tokens[parser->toknext++];
- tok->start = tok->end = -1;
- tok->size = 0;
-#ifdef JSMN_PARENT_LINKS
- tok->parent = -1;
-#endif
- return tok;
-}
-
-/**
- * Fills token type and boundaries.
- */
-static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
- int start, int end) {
- token->type = type;
- token->start = start;
- token->end = end;
- token->size = 0;
-}
-
-/**
- * Fills next available token with JSON primitive.
- */
-static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
- jsmntok_t *tokens, size_t num_tokens) {
- jsmntok_t *token;
- int start;
-
- start = parser->pos;
-
- for (; js[parser->pos] != '\0'; parser->pos++) {
- switch (js[parser->pos]) {
-#ifndef JSMN_STRICT
- /* In strict mode primitive must be followed by "," or "}" or "]" */
- case ':':
-#endif
- case '\t' : case '\r' : case '\n' : case ' ' :
- case ',' : case ']' : case '}' :
- goto found;
- }
- if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
- parser->pos = start;
- return JSMN_ERROR_INVAL;
- }
- }
-#ifdef JSMN_STRICT
- /* In strict mode primitive must be followed by a comma/object/array */
- parser->pos = start;
- return JSMN_ERROR_PART;
-#endif
-
-found:
- token = jsmn_alloc_token(parser, tokens, num_tokens);
- if (token == NULL) {
- parser->pos = start;
- return JSMN_ERROR_NOMEM;
- }
- jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
-#ifdef JSMN_PARENT_LINKS
- token->parent = parser->toksuper;
-#endif
- parser->pos--;
- return JSMN_SUCCESS;
-}
-
-/**
- * Filsl next token with JSON string.
- */
-static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
- jsmntok_t *tokens, size_t num_tokens) {
- jsmntok_t *token;
-
- int start = parser->pos;
-
- parser->pos++;
-
- /* Skip starting quote */
- for (; js[parser->pos] != '\0'; parser->pos++) {
- char c = js[parser->pos];
-
- /* Quote: end of string */
- if (c == '\"') {
- token = jsmn_alloc_token(parser, tokens, num_tokens);
- if (token == NULL) {
- parser->pos = start;
- return JSMN_ERROR_NOMEM;
- }
- jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
-#ifdef JSMN_PARENT_LINKS
- token->parent = parser->toksuper;
-#endif
- return JSMN_SUCCESS;
- }
-
- /* Backslash: Quoted symbol expected */
- if (c == '\\') {
- parser->pos++;
- switch (js[parser->pos]) {
- /* Allowed escaped symbols */
- case '\"': case '/' : case '\\' : case 'b' :
- case 'f' : case 'r' : case 'n' : case 't' :
- break;
- /* Allows escaped symbol \uXXXX */
- case 'u':
- /* TODO */
- break;
- /* Unexpected symbol */
- default:
- parser->pos = start;
- return JSMN_ERROR_INVAL;
- }
- }
- }
- parser->pos = start;
- return JSMN_ERROR_PART;
-}
-
-/**
- * Parse JSON string and fill tokens.
- */
-jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, jsmntok_t *tokens,
- unsigned int num_tokens) {
- jsmnerr_t r;
- int i;
- jsmntok_t *token;
-
- for (; js[parser->pos] != '\0'; parser->pos++) {
- char c;
- jsmntype_t type;
-
- c = js[parser->pos];
- switch (c) {
- case '{': case '[':
- token = jsmn_alloc_token(parser, tokens, num_tokens);
- if (token == NULL)
- return JSMN_ERROR_NOMEM;
- if (parser->toksuper != -1) {
- tokens[parser->toksuper].size++;
-#ifdef JSMN_PARENT_LINKS
- token->parent = parser->toksuper;
-#endif
- }
- token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
- token->start = parser->pos;
- parser->toksuper = parser->toknext - 1;
- break;
- case '}': case ']':
- type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
-#ifdef JSMN_PARENT_LINKS
- if (parser->toknext < 1) {
- return JSMN_ERROR_INVAL;
- }
- token = &tokens[parser->toknext - 1];
- for (;;) {
- if (token->start != -1 && token->end == -1) {
- if (token->type != type) {
- return JSMN_ERROR_INVAL;
- }
- token->end = parser->pos + 1;
- parser->toksuper = token->parent;
- break;
- }
- if (token->parent == -1) {
- break;
- }
- token = &tokens[token->parent];
- }
-#else
- for (i = parser->toknext - 1; i >= 0; i--) {
- token = &tokens[i];
- if (token->start != -1 && token->end == -1) {
- if (token->type != type) {
- return JSMN_ERROR_INVAL;
- }
- parser->toksuper = -1;
- token->end = parser->pos + 1;
- break;
- }
- }
- /* Error if unmatched closing bracket */
- if (i == -1) return JSMN_ERROR_INVAL;
- for (; i >= 0; i--) {
- token = &tokens[i];
- if (token->start != -1 && token->end == -1) {
- parser->toksuper = i;
- break;
- }
- }
-#endif
- break;
- case '\"':
- r = jsmn_parse_string(parser, js, tokens, num_tokens);
- if (r < 0) return r;
- if (parser->toksuper != -1)
- tokens[parser->toksuper].size++;
- break;
- case '\t' : case '\r' : case '\n' : case ':' : case ',': case ' ':
- break;
-#ifdef JSMN_STRICT
- /* In strict mode primitives are: numbers and booleans */
- case '-': case '0': case '1' : case '2': case '3' : case '4':
- case '5': case '6': case '7' : case '8': case '9':
- case 't': case 'f': case 'n' :
-#else
- /* In non-strict mode every unquoted value is a primitive */
- default:
-#endif
- r = jsmn_parse_primitive(parser, js, tokens, num_tokens);
- if (r < 0) return r;
- if (parser->toksuper != -1)
- tokens[parser->toksuper].size++;
- break;
-
-#ifdef JSMN_STRICT
- /* Unexpected char in strict mode */
- default:
- return JSMN_ERROR_INVAL;
-#endif
-
- }
- }
-
- for (i = parser->toknext - 1; i >= 0; i--) {
- /* Unmatched opened object or array */
- if (tokens[i].start != -1 && tokens[i].end == -1) {
- return JSMN_ERROR_PART;
- }
- }
-
- return JSMN_SUCCESS;
-}
-
-/**
- * Creates a new parser based over a given buffer with an array of tokens
- * available.
- */
-void jsmn_init(jsmn_parser *parser) {
- parser->pos = 0;
- parser->toknext = 0;
- parser->toksuper = -1;
-}
-
diff --git a/src/jsmn.h b/src/jsmn.h
deleted file mode 100644
index f12dc5a..0000000
--- a/src/jsmn.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * jsmn.h
- * Simple JSON parser (header file)
- *
- * Copyright (c) 2010 Serge A. Zaitsev
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#ifndef __JSMN_H_
-#define __JSMN_H_
-
-/**
- * JSON type identifier. Basic types are:
- * o Object
- * o Array
- * o String
- * o Other primitive: number, boolean (true/false) or null
- */
-typedef enum {
- JSMN_PRIMITIVE = 0,
- JSMN_OBJECT = 1,
- JSMN_ARRAY = 2,
- JSMN_STRING = 3
-} jsmntype_t;
-
-typedef enum {
- /* Not enough tokens were provided */
- JSMN_ERROR_NOMEM = -1,
- /* Invalid character inside JSON string */
- JSMN_ERROR_INVAL = -2,
- /* The string is not a full JSON packet, more bytes expected */
- JSMN_ERROR_PART = -3,
- /* Everything was fine */
- JSMN_SUCCESS = 0
-} jsmnerr_t;
-
-/**
- * JSON token description.
- * @param type type (object, array, string etc.)
- * @param start start position in JSON data string
- * @param end end position in JSON data string
- */
-typedef struct {
- jsmntype_t type;
- int start;
- int end;
- int size;
-#ifdef JSMN_PARENT_LINKS
- int parent;
-#endif
-} jsmntok_t;
-
-/**
- * JSON parser. Contains an array of token blocks available. Also stores
- * the string being parsed now and current position in that string
- */
-typedef struct {
- unsigned int pos; /* offset in the JSON string */
- int toknext; /* next token to allocate */
- int toksuper; /* superior token node, e.g parent object or array */
-} jsmn_parser;
-
-/**
- * Create JSON parser over an array of tokens
- */
-void jsmn_init(jsmn_parser *parser);
-
-/**
- * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
- * a single JSON object.
- */
-jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js,
- jsmntok_t *tokens, unsigned int num_tokens);
-
-#endif /* __JSMN_H_ */
diff --git a/src/json_plist.c b/src/json_plist.c
deleted file mode 100644
index 7bbead0..0000000
--- a/src/json_plist.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * json_plist.c
- * JSON/property list functions
- *
- * Copyright (c) 2013 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <jsmn.h>
-#include <plist/plist.h>
-
-#include "json_plist.h"
-
-static plist_t parse_primitive(const char* js, jsmntok_t* tokens, int* index);
-static plist_t parse_string(const char* js, jsmntok_t* tokens, int* index);
-static plist_t parse_array(const char* js, jsmntok_t* tokens, int* index);
-static plist_t parse_object(const char* js, jsmntok_t* tokens, int* index);
-
-static char* get_string_value(const char* js, jsmntok_t token)
-{
- int len = (token.end - token.start);
- char* str = malloc(len+1);
- memcpy(str, js + token.start, len);
- str[len] = 0;
- return str;
-}
-
-static plist_t parse_primitive(const char* js, jsmntok_t* tokens, int* index)
-{
- if (tokens[*index].type != JSMN_PRIMITIVE) {
- fprintf(stderr, "%s: ERROR: token type != JSMN_PRIMITIVE?!\n", __func__);
- return NULL;
- }
- plist_t val = NULL;
- char* strval = get_string_value(js, tokens[*index]);
- if (strval[0] == 'f') {
- val = plist_new_bool(0);
- } else if (strval[0] == 't') {
- val = plist_new_bool(1);
- } else if ((strval[0] == '-') || ((strval[0] >= '0') && (strval[0] <= '9'))) {
- val = plist_new_uint(strtoll(strval, NULL, 10));
- } else {
- fprintf(stderr, "%s: WARNING: invalid primitive value '%s' encountered, will return as string\n", __func__, strval);
- val = plist_new_string(strval);
- }
- free(strval);
- (*index)++;
- return val;
-}
-
-static plist_t parse_string(const char* js, jsmntok_t* tokens, int* index)
-{
- if (tokens[*index].type != JSMN_STRING) {
- fprintf(stderr, "%s: ERROR: token type != JSMN_STRING?!\n", __func__);
- return NULL;
- }
- char* str = get_string_value(js, tokens[*index]);
- plist_t val = plist_new_string(str);
- free(str);
- (*index)++;
- return val;
-}
-
-static plist_t parse_array(const char* js, jsmntok_t* tokens, int* index)
-{
- if (tokens[*index].type != JSMN_ARRAY) {
- fprintf(stderr, "%s: ERROR: token type != JSMN_ARRAY?!\n", __func__);
- return NULL;
- }
- plist_t arr = plist_new_array();
- int num_tokens = tokens[*index].size;
- int num;
- int j = (*index)+1;
- for (num = 0; num < num_tokens; num++) {
- plist_t val = NULL;
- switch (tokens[j].type) {
- case JSMN_OBJECT:
- val = parse_object(js, tokens, &j);
- break;
- case JSMN_ARRAY:
- val = parse_array(js, tokens, &j);
- break;
- case JSMN_STRING:
- val = parse_string(js, tokens, &j);
- break;
- case JSMN_PRIMITIVE:
- val = parse_primitive(js, tokens, &j);
- break;
- default:
- break;
- }
- if (val) {
- plist_array_append_item(arr, val);
- }
- }
- *(index) = j;
- return arr;
-}
-
-static plist_t parse_object(const char* js, jsmntok_t* tokens, int* index)
-{
- if (tokens[*index].type != JSMN_OBJECT) {
- fprintf(stderr, "%s: ERROR: token type != JSMN_OBJECT?!\n", __func__);
- return NULL;
- }
- plist_t obj = plist_new_dict();
- int num_tokens = tokens[*index].size;
- int num;
- int j = (*index)+1;
- for (num = 0; num < num_tokens; num++) {
- if (tokens[j].type == JSMN_STRING) {
- char* key = get_string_value(js, tokens[j]);
- plist_t val = NULL;
- j++;
- num++;
- switch (tokens[j].type) {
- case JSMN_OBJECT:
- val = parse_object(js, tokens, &j);
- break;
- case JSMN_ARRAY:
- val = parse_array(js, tokens, &j);
- break;
- case JSMN_STRING:
- val = parse_string(js, tokens, &j);
- break;
- case JSMN_PRIMITIVE:
- val = parse_primitive(js, tokens, &j);
- break;
- default:
- break;
- }
- if (val) {
- plist_dict_set_item(obj, key, val);
- }
- free(key);
- } else {
- fprintf(stderr, "%s: keys must be of type STRING\n", __func__);
- return NULL;
- }
- }
- (*index) = j;
- return obj;
-}
-
-plist_t json_to_plist(const char* json_string)
-{
- jsmn_parser parser;
- jsmn_init(&parser);
- int maxtoks = 256;
- jsmntok_t *tokens;
-
- if (!json_string) {
- fprintf(stderr, "%s: ERROR: no JSON string given.\n", __func__);
- return NULL;
- }
-
- tokens = malloc(sizeof(jsmntok_t)*maxtoks);
- if (!tokens) {
- fprintf(stderr, "%s: Out of memory\n", __func__);
- return NULL;
- }
-
- int r = 0;
-reparse:
- r = jsmn_parse(&parser, json_string, tokens, maxtoks);
- if (r == JSMN_ERROR_NOMEM) {
- //printf("not enough tokens (%d), retrying...\n", maxtoks);
- maxtoks+=256;
- jsmntok_t* newtokens = realloc(tokens, sizeof(jsmntok_t)*maxtoks);
- if (newtokens) {
- tokens = newtokens;
- goto reparse;
- }
- }
-
- switch(r) {
- case JSMN_ERROR_NOMEM:
- fprintf(stderr, "%s: ERROR: Out of memory...\n", __func__);
- return NULL;
- case JSMN_ERROR_INVAL:
- fprintf(stderr, "%s: ERROR: Invalid character inside JSON string\n", __func__);
- return NULL;
- case JSMN_ERROR_PART:
- fprintf(stderr, "%s: ERROR: The string is not a full JSON packet, more bytes expected\n", __func__);
- return NULL;
- default:
- break;
- }
-
- int startindex = 0;
- plist_t plist = NULL;
- switch (tokens[startindex].type) {
- case JSMN_PRIMITIVE:
- plist = parse_primitive(json_string, tokens, &startindex);
- break;
- case JSMN_STRING:
- plist = parse_string(json_string, tokens, &startindex);
- break;
- case JSMN_ARRAY:
- plist = parse_array(json_string, tokens, &startindex);
- break;
- case JSMN_OBJECT:
- plist = parse_object(json_string, tokens, &startindex);
- break;
- default:
- break;
- }
-
- free(tokens);
-
- return plist;
-}
-
diff --git a/src/json_plist.h b/src/json_plist.h
deleted file mode 100644
index d6eec0b..0000000
--- a/src/json_plist.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * json_plist.h
- * JSON/property list functions (header file)
- *
- * Copyright (c) 2013 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
- */
-#ifndef __JSON_PLIST_H
-#define __JSON_PLIST_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-plist_t json_to_plist(const char* json_string);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/src/normal.c b/src/normal.c
index 15d3e29..e699bbe 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -29,6 +29,7 @@
#include <libimobiledevice/libimobiledevice.h>
#include <libimobiledevice/lockdown.h>
#include <libimobiledevice/preboard.h>
+#include <usbmuxd.h>
#include "common.h"
#include "normal.h"
@@ -41,6 +42,7 @@ static int normal_idevice_new(struct idevicerestore_client_t* client, idevice_t*
idevice_t dev = NULL;
idevice_error_t device_error;
lockdownd_client_t lockdown = NULL;
+ plist_t node = NULL;
*device = NULL;
@@ -65,6 +67,10 @@ static int normal_idevice_new(struct idevicerestore_client_t* client, idevice_t*
return -1;
}
free(type);
+ if (lockdownd_get_value(lockdown, NULL, "UniqueChipID", &node) == LOCKDOWN_E_SUCCESS) {
+ plist_get_uint_val(node, &client->ecid);
+ plist_free(node);
+ }
lockdownd_client_free(lockdown);
lockdown = NULL;
@@ -107,7 +113,7 @@ static int normal_idevice_new(struct idevicerestore_client_t* client, idevice_t*
}
free(type);
- plist_t node = NULL;
+ node = NULL;
if ((lockdownd_get_value(lockdown, NULL, "UniqueChipID", &node) != LOCKDOWN_E_SUCCESS) || !node || (plist_get_node_type(node) != PLIST_UINT)){
if (node) {
plist_free(node);
@@ -228,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);
@@ -280,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;
}
@@ -320,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);
@@ -331,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);
}
@@ -362,27 +365,26 @@ int normal_is_image4_supported(struct idevicerestore_client_t* client)
return bval;
}
-int normal_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid)
+int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info)
{
- plist_t unique_chip_node = normal_get_lockdown_value(client, NULL, "UniqueChipID");
- if (!unique_chip_node || plist_get_node_type(unique_chip_node) != PLIST_UINT) {
- error("ERROR: Unable to get ECID\n");
- return -1;
- }
- plist_get_uint_val(unique_chip_node, ecid);
- plist_free(unique_chip_node);
+ uint8_t has_telephony_capability = 0;
+ plist_t node;
- return 0;
-}
+ node = normal_get_lockdown_value(client, NULL, "TelephonyCapability");
+ plist_get_bool_val(node, &has_telephony_capability);
+ plist_free(node);
-int normal_get_preflight_info(struct idevicerestore_client_t* client, plist_t *preflight_info)
-{
- plist_t node = normal_get_lockdown_value(client, NULL, "FirmwarePreflightInfo");
- if (!node || plist_get_node_type(node) != PLIST_DICT) {
- error("ERROR: Unable to get FirmwarePreflightInfo\n");
- return -1;
+ if (has_telephony_capability) {
+ node = normal_get_lockdown_value(client, NULL, "FirmwarePreflightInfo");
+ if (!node || plist_get_node_type(node) != PLIST_DICT) {
+ error("ERROR: Unable to get FirmwarePreflightInfo\n");
+ return -1;
+ }
+ *preflight_info = node;
+ } else {
+ debug("DEBUG: Device does not have TelephonyCapability, no FirmwarePreflightInfo\n");
+ *preflight_info = NULL;
}
- *preflight_info = node;
return 0;
}
@@ -460,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"
@@ -489,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;
@@ -577,7 +579,6 @@ int normal_handle_commit_stashbag(struct idevicerestore_client_t* client, plist_
if (perr != PREBOARD_E_SUCCESS) {
error("ERROR: could not receive from preboard service (%d)\n", perr);
} else {
- int commit_complete = 0;
plist_t node = plist_dict_get_item(pl, "Error");
if (node) {
char *strval = NULL;
@@ -587,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/normal.h b/src/normal.h
index f438f9b..7741ac5 100644
--- a/src/normal.h
+++ b/src/normal.h
@@ -35,10 +35,9 @@ extern "C" {
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_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid);
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 b6a6f51..e3fb4d1 100644
--- a/src/recovery.c
+++ b/src/recovery.c
@@ -124,7 +124,7 @@ int recovery_enter_restore(struct idevicerestore_client_t* client, plist_t build
{
if (client->build_major >= 8) {
client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1 -progress");
- } else if (client->build_major >= 20) {
+ } else if (client->macos_variant) {
client->restore_boot_args = strdup("rd=md0 nand-enable-reformat=1 -progress -restore");
}
@@ -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) {
@@ -344,7 +358,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;
@@ -498,7 +512,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", 1);
if (recovery_error != IRECV_E_SUCCESS) {
error("ERROR: Unable to execute %s\n", component);
return -1;
@@ -507,24 +521,6 @@ int recovery_send_kernelcache(struct idevicerestore_client_t* client, plist_t bu
return 0;
}
-int recovery_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid)
-{
- if(client->recovery == NULL) {
- if (recovery_client_new(client) < 0) {
- return -1;
- }
- }
-
- const struct irecv_device_info *device_info = irecv_get_device_info(client->recovery->client);
- if (!device_info) {
- return -1;
- }
-
- *ecid = device_info->ecid;
-
- return 0;
-}
-
int recovery_is_image4_supported(struct idevicerestore_client_t* client)
{
if(client->recovery == NULL) {
@@ -541,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) {
@@ -566,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) {
@@ -593,7 +589,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;
}
diff --git a/src/recovery.h b/src/recovery.h
index 154d7d1..d7413e0 100644
--- a/src/recovery.h
+++ b/src/recovery.h
@@ -54,10 +54,9 @@ int recovery_send_loaded_by_iboot(struct idevicerestore_client_t* client, plist_
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_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid);
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
diff --git a/src/restore.c b/src/restore.c
index 7b61766..050ee3b 100644
--- a/src/restore.c
+++ b/src/restore.c
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <libgen.h>
#include <libimobiledevice/restore.h>
#ifdef HAVE_REVERSE_PROXY
#include <libimobiledevice/reverse_proxy.h>
@@ -278,18 +279,12 @@ irecv_device_t restore_get_irecv_device(struct idevicerestore_client_t* client)
}
if (client->srnm == NULL) {
- restore_error = restored_get_value(restore, "SerialNumber", &node);
- if (restore_error != RESTORE_E_SUCCESS || !node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to get SerialNumber from restored\n");
- restored_client_free(restore);
- idevice_free(device);
- return NULL;
+ if (restored_get_value(restore, "SerialNumber", &node) == RESTORE_E_SUCCESS) {
+ plist_get_string_val(node, &client->srnm);
+ info("INFO: device serial number is %s\n", client->srnm);
+ plist_free(node);
+ node = NULL;
}
-
- plist_get_string_val(node, &client->srnm);
- info("INFO: device serial number is %s\n", client->srnm);
- plist_free(node);
- node = NULL;
}
restore_error = restored_get_value(restore, "HardwareModel", &node);
@@ -379,8 +374,8 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con
if (!client) {
return 0;
}
- if (!client->srnm) {
- error("ERROR: %s: no SerialNumber given in client data\n", __func__);
+ if (!client->ecid) {
+ error("ERROR: %s: no ECID given in client data\n", __func__);
return 0;
}
@@ -413,35 +408,35 @@ static int restore_is_current_device(struct idevicerestore_client_t* client, con
return 0;
}
- plist_t node = NULL;
- restore_error = restored_get_value(restored, "SerialNumber", &node);
- if ((restore_error != RESTORE_E_SUCCESS) || !node || (plist_get_node_type(node) != PLIST_STRING)) {
- error("ERROR: %s: Unable to get SerialNumber from restored\n", __func__);
+ plist_t hwinfo = NULL;
+ restore_error = restored_query_value(restored, "HardwareInfo", &hwinfo);
+ if ((restore_error != RESTORE_E_SUCCESS) || !hwinfo) {
+ error("ERROR: %s: Unable to get HardwareInfo from restored\n", __func__);
restored_client_free(restored);
idevice_free(device);
- if (node) {
- plist_free(node);
- }
+ plist_free(hwinfo);
return 0;
}
restored_client_free(restored);
idevice_free(device);
- char* this_srnm = NULL;
- plist_get_string_val(node, &this_srnm);
- plist_free(node);
+ uint64_t this_ecid = 0;
+ plist_t node = plist_dict_get_item(hwinfo, "UniqueChipID");
+ if (node && plist_get_node_type(node) == PLIST_UINT) {
+ plist_get_uint_val(node, &this_ecid);
+ }
+ plist_free(hwinfo);
- if (!this_srnm) {
+ if (this_ecid == 0) {
+ error("ERROR: %s: Unable to get ECID from restored\n", __func__);
return 0;
}
- return (strcasecmp(this_srnm, client->srnm) == 0);
+ return (this_ecid == client->ecid);
}
int restore_open_with_timeout(struct idevicerestore_client_t* client)
{
- int i = 0;
- int attempts = 180;
char *type = NULL;
uint64_t version = 0;
idevice_t device = NULL;
@@ -450,17 +445,17 @@ int restore_open_with_timeout(struct idevicerestore_client_t* client)
restored_error_t restore_error = RESTORE_E_SUCCESS;
// no context exists so bail
- if(client == NULL) {
+ if (client == NULL) {
return -1;
}
- if(client->srnm == NULL) {
- error("ERROR: no SerialNumber in client data!\n");
+ if (client->ecid == 0) {
+ error("ERROR: no ECID in client data!\n");
return -1;
}
// create our restore client if it doesn't yet exist
- if(client->restore == NULL) {
+ if (client->restore == NULL) {
client->restore = (struct restore_client_t*) malloc(sizeof(struct restore_client_t));
if(client->restore == NULL) {
error("ERROR: Out of memory\n");
@@ -748,6 +743,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;
@@ -902,13 +898,37 @@ 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_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;
+ }
+ if (client->filesystem) {
+ char* path = strdup(client->filesystem);
+ const char* fsname_base = path_get_basename(path);
+ char* parent_dir = dirname(path);
+ ipsw_dummy = ipsw_open(parent_dir);
+ file = ipsw_file_open(ipsw_dummy, fsname_base);
+ free(path);
+ } else {
+ 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);
+ ipsw_close(ipsw_dummy);
error("ERROR: Unable to connect to ASR\n");
return -1;
}
@@ -919,7 +939,9 @@ 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);
+ ipsw_close(ipsw_dummy);
error("ERROR: ASR was unable to validate the filesystem\n");
asr_free(asr);
return -1;
@@ -929,11 +951,16 @@ 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);
+ 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");
asr_free(asr);
@@ -1109,7 +1136,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)
+int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message)
{
char* llb_path = NULL;
char* llb_filename = NULL;
@@ -1127,10 +1154,15 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
unsigned char* nor_data = NULL;
plist_t norimage = NULL;
plist_t firmware_files = NULL;
- uint32_t i;
+ int flash_version_1 = 0;
info("About to send NORData...\n");
+ plist_t arguments = plist_dict_get_item(message, "Arguments");
+ if (arguments && plist_get_node_type(arguments) == PLIST_DICT) {
+ flash_version_1 = plist_dict_get_item(arguments, "FlashVersion1") ? 1 : 0;
+ }
+
if (client->tss) {
if (tss_response_get_path_by_entry(client->tss, "LLB", &llb_path) < 0) {
debug("NOTE: Could not get LLB path from TSS data, will fetch from build identity\n");
@@ -1247,12 +1279,10 @@ 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((char*)llb_data, llb_size));
free(llb_data);
- if (client->build_major >= 20) {
- // Starting with M1 macs, it seems that NorImageData is now a dict.
- // Sending an array like previous versions results in restore success but the machine will SOS after rebooting.
+ if (flash_version_1) {
norimage = plist_new_dict();
} else {
norimage = plist_new_array();
@@ -1308,14 +1338,14 @@ int restore_send_nor(restored_client_t restore, struct idevicerestore_client_t*
component_data = NULL;
component_size = 0;
- if (client->build_major >= 20) {
- plist_dict_set_item(norimage, component, plist_new_data((char*)nor_data, (uint64_t)nor_size));
+ if (flash_version_1) {
+ 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((char*)nor_data, (uint64_t)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((char*)nor_data, (uint64_t)nor_size));
+ plist_array_append_item(norimage, plist_new_data((char*)nor_data, nor_size));
}
}
@@ -1351,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((char*)personalized_data, personalized_size));
free(personalized_data);
personalized_data = NULL;
personalized_size = 0;
@@ -1376,7 +1406,32 @@ 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((char*)personalized_data, personalized_size));
+ free(personalized_data);
+ personalized_data = NULL;
+ 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, personalized_size));
free(personalized_data);
personalized_data = NULL;
personalized_size = 0;
@@ -1455,12 +1510,12 @@ 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;
int zerr = 0;
- int zindex = -1;
+ int64_t zindex = -1;
struct zip_stat zstat;
struct zip_file* zfile = NULL;
struct zip* za = NULL;
@@ -1482,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;
@@ -1511,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;
}
@@ -1552,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, (char**)&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;
@@ -1571,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);
@@ -1597,7 +1649,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;
}
@@ -1615,9 +1667,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]) {
@@ -1651,13 +1704,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;
}
@@ -1684,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, (char**)&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;
@@ -1696,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);
@@ -1716,28 +1766,26 @@ 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;
}
} else {
// add BBTicket as bbticket.der
- blob = NULL;
blob_size = 0;
- plist_get_data_val(bbticket, (char**)&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_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;
}
@@ -1768,7 +1816,6 @@ leave:
mbn_free(mbn);
fls_free(fls);
free(buffer);
- free(blob);
return res;
}
@@ -1823,7 +1870,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);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
/* create baseband request */
plist_t request = tss_request_new(NULL);
@@ -1914,7 +1961,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;
@@ -1978,7 +2025,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);
@@ -2108,7 +2155,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;
@@ -2117,6 +2164,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");
@@ -2125,7 +2173,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 || chip_id == 0x36) {
comp_name = "SE,UpdatePayload";
} else {
info("WARNING: Unknown SE,ChipID 0x%" PRIx64 " detected. Restore might fail.\n", (uint64_t)chip_id);
@@ -2140,6 +2188,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;
@@ -2164,13 +2220,13 @@ 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);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
/* add SE,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, 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);
@@ -2183,13 +2239,15 @@ 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));
+ plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size));
free(component_data);
component_data = NULL;
component_size = 0;
@@ -2207,7 +2265,6 @@ static plist_t restore_get_savage_firmware_data(restored_client_t restore, struc
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
/* create Savage request */
@@ -2220,7 +2277,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);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
/* add Savage,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
@@ -2281,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((char*)component_data, (uint64_t) 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;
@@ -2293,13 +2350,11 @@ static plist_t restore_get_yonkers_firmware_data(restored_client_t restore, stru
{
char *comp_name = NULL;
char *comp_path = NULL;
- plist_t comp_node = NULL;
unsigned char* component_data = NULL;
unsigned int component_size = 0;
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
/* create Yonkers request */
@@ -2314,7 +2369,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);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
/* add Yonkers,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
@@ -2365,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((char *)component_data, (uint64_t)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);
@@ -2375,11 +2430,10 @@ 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;
- plist_t comp_node = NULL;
unsigned char* component_data = NULL;
unsigned int component_size = 0;
ftab_t ftab = NULL;
@@ -2388,7 +2442,6 @@ static plist_t restore_get_rose_firmware_data(restored_client_t restore, struct
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
/* create Rose request */
@@ -2402,7 +2455,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);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1));
if (client->image4supported) {
@@ -2412,8 +2465,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(&parameters, 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(&parameters, p_info);
+ }
/* add required tags for Rose TSS request */
tss_request_add_rose_tags(request, parameters, NULL);
@@ -2435,6 +2494,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);
@@ -2504,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((char *)component_data, (uint64_t)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;
@@ -2516,13 +2581,11 @@ static plist_t restore_get_veridian_firmware_data(restored_client_t restore, str
{
char *comp_name = "BMU,FirmwareMap";
char *comp_path = NULL;
- plist_t comp_node = NULL;
unsigned char* component_data = NULL;
unsigned int component_size = 0;
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
/* create Veridian request */
@@ -2536,7 +2599,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);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
/* add BMU,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
@@ -2604,23 +2667,76 @@ 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(bin_plist, bin_size));
free(bin_plist);
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";
char *comp_path = NULL;
- plist_t comp_node = NULL;
unsigned char* component_data = NULL;
unsigned int component_size = 0;
plist_t parameters = NULL;
plist_t request = NULL;
plist_t response = NULL;
- plist_t node = NULL;
int ret;
/* create Baobab request */
@@ -2634,7 +2750,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);
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
/* add Baobab,* tags from info dictionary to parameters */
plist_dict_merge(&parameters, p_info);
@@ -2673,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((char *)component_data, (uint64_t)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;
@@ -2681,6 +2797,305 @@ static plist_t restore_get_tcon_firmware_data(restored_client_t restore, struct
return response;
}
+static plist_t restore_get_timer_firmware_data(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t p_info)
+{
+ char comp_name[64];
+ char *comp_path = NULL;
+ unsigned char* component_data = NULL;
+ unsigned int component_size = 0;
+ ftab_t ftab = NULL;
+ ftab_t rftab = NULL;
+ uint32_t ftag = 0;
+ plist_t parameters = NULL;
+ plist_t request = NULL;
+ plist_t response = NULL;
+ const char* ticket_name = NULL;
+ uint32_t tag = 0;
+ int ret;
+
+ /* create Timer request */
+ request = tss_request_new(NULL);
+ if (request == NULL) {
+ error("ERROR: Unable to create Timer TSS request\n");
+ return NULL;
+ }
+
+ parameters = plist_new_dict();
+
+ /* add manifest for current build_identity to parameters */
+ tss_parameters_add_from_manifest(parameters, build_identity, true);
+
+ plist_dict_set_item(parameters, "ApProductionMode", plist_new_bool(1));
+ if (client->image4supported) {
+ plist_dict_set_item(parameters, "ApSecurityMode", plist_new_bool(1));
+ plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(1));
+ } else {
+ plist_dict_set_item(parameters, "ApSupportsImg4", plist_new_bool(0));
+ }
+
+ /* add Timer,* tags from info dictionary to parameters */
+ plist_t info_array = plist_dict_get_item(p_info, "InfoArray");
+ if (!info_array) {
+ error("ERROR: Could not find InfoArray in info dictionary\n");
+ plist_free(parameters);
+ return NULL;
+ } else {
+ plist_t info_dict = plist_array_get_item(info_array, 0);
+ plist_t hwid = plist_dict_get_item(info_dict, "HardwareID");
+ tag = (uint32_t)plist_dict_get_uint(info_dict, "TagNumber");
+ char key[64];
+
+ plist_dict_set_item(parameters, "TagNumber", plist_new_uint(tag));
+ plist_t node = plist_dict_get_item(info_dict, "TicketName");
+ if (node) {
+ ticket_name = plist_get_string_ptr(node, NULL);
+ plist_dict_set_item(parameters, "TicketName", plist_copy(node));
+ }
+
+ sprintf(key, "Timer,ChipID,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "ChipID");
+
+ sprintf(key, "Timer,BoardID,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "BoardID");
+
+ sprintf(key, "Timer,ECID,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "ECID");
+
+ sprintf(key, "Timer,Nonce,%u", tag);
+ plist_dict_copy_data(parameters, hwid, key, "Nonce");
+
+ sprintf(key, "Timer,SecurityMode,%u", tag);
+ plist_dict_copy_bool(parameters, hwid, key, "SecurityMode");
+
+ sprintf(key, "Timer,SecurityDomain,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "SecurityDomain");
+
+ sprintf(key, "Timer,ProductionMode,%u", tag);
+ plist_dict_copy_uint(parameters, hwid, key, "ProductionStatus");
+ }
+ plist_t ap_info = plist_dict_get_item(p_info, "APInfo");
+ if (!ap_info) {
+ error("ERROR: Could not find APInfo in info dictionary\n");
+ plist_free(parameters);
+ return NULL;
+ } else {
+ plist_dict_merge(&parameters, ap_info);
+ }
+
+ /* add required tags for Timer TSS request */
+ tss_request_add_timer_tags(request, parameters, NULL);
+
+ plist_free(parameters);
+
+ info("Sending %s TSS request...\n", ticket_name);
+ response = tss_request_send(request, client->tss_url);
+ plist_free(request);
+ if (response == NULL) {
+ error("ERROR: Unable to fetch %s\n", ticket_name);
+ return NULL;
+ }
+
+ if (plist_dict_get_item(response, ticket_name)) {
+ info("Received %s\n", ticket_name);
+ } else {
+ error("ERROR: No '%s' in TSS response, this might not work\n", ticket_name);
+ }
+
+ sprintf(comp_name, "Timer,RTKitOS,%u", tag);
+ if (build_identity_has_component(build_identity, comp_name)) {
+ if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) {
+ error("ERROR: Unable to get path for '%s' component\n", comp_name);
+ return NULL;
+ }
+ ret = extract_component(client->ipsw, comp_path, &component_data, &component_size);
+ free(comp_path);
+ comp_path = NULL;
+ if (ret < 0) {
+ error("ERROR: Unable to extract '%s' component\n", comp_name);
+ return NULL;
+ }
+ if (ftab_parse(component_data, component_size, &ftab, &ftag) != 0) {
+ free(component_data);
+ error("ERROR: Failed to parse '%s' component data.\n", comp_name);
+ return NULL;
+ }
+ free(component_data);
+ component_data = NULL;
+ component_size = 0;
+ if (ftag != 'rkos') {
+ error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos');
+ }
+ } else {
+ info("NOTE: Build identity does not have a '%s' component.\n", comp_name);
+ }
+
+ sprintf(comp_name, "Timer,RestoreRTKitOS,%u", tag);
+ if (build_identity_has_component(build_identity, comp_name)) {
+ if (build_identity_get_component_path(build_identity, comp_name, &comp_path) < 0) {
+ ftab_free(ftab);
+ error("ERROR: Unable to get path for '%s' component\n", comp_name);
+ return NULL;
+ }
+ ret = extract_component(client->ipsw, comp_path, &component_data, &component_size);
+ free(comp_path);
+ comp_path = NULL;
+ if (ret < 0) {
+ ftab_free(ftab);
+ error("ERROR: Unable to extract '%s' component\n", comp_name);
+ return NULL;
+ }
+
+ ftag = 0;
+ if (ftab_parse(component_data, component_size, &rftab, &ftag) != 0) {
+ free(component_data);
+ ftab_free(ftab);
+ error("ERROR: Failed to parse '%s' component data.\n", comp_name);
+ return NULL;
+ }
+ free(component_data);
+ component_data = NULL;
+ component_size = 0;
+ if (ftag != 'rkos') {
+ error("WARNING: Unexpected tag 0x%08x, expected 0x%08x; continuing anyway.\n", ftag, 'rkos');
+ }
+
+ if (ftab_get_entry_ptr(rftab, 'rrko', &component_data, &component_size) == 0) {
+ ftab_add_entry(ftab, 'rrko', component_data, component_size);
+ } else {
+ error("ERROR: Could not find 'rrko' entry in ftab. This will probably break things.\n");
+ }
+ ftab_free(rftab);
+ component_data = NULL;
+ component_size = 0;
+ } else {
+ info("NOTE: Build identity does not have a '%s' component.\n", comp_name);
+ }
+
+ ftab_write(ftab, &component_data, &component_size);
+ ftab_free(ftab);
+
+ plist_dict_set_item(response, "FirmwareData", plist_new_data((char*)component_data, component_size));
+ free(component_data);
+ component_data = NULL;
+ component_size = 0;
+
+ 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)
+{
+ plist_t parameters = NULL;
+ 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 = "Cryptex1,Ticket";
+ 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);
+ }
+ }
+
+ /* create Cryptex1 request */
+ request = tss_request_new(NULL);
+ if (request == NULL) {
+ error("ERROR: Unable to create %s TSS request\n", s_updater_name);
+ return NULL;
+ }
+
+ parameters = plist_new_dict();
+
+ /* merge data from MessageArgInfo */
+ plist_dict_merge(&parameters, p_info);
+
+ /* 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));
+ }
+ }
+ }
+
+ /* 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(&parameters, device_generated_request);
+
+ /* add Cryptex1 tags to request */
+ tss_request_add_cryptex_tags(request, parameters, NULL);
+
+ plist_free(parameters);
+
+ 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 int restore_send_firmware_updater_preflight(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity, plist_t message)
+{
+ plist_t dict = NULL;
+ int restore_error;
+
+ if (idevicerestore_debug) {
+ debug("DEBUG: %s: Got FirmwareUpdaterPreflight request:\n", __func__);
+ debug_plist(message);
+ }
+
+ dict = plist_new_dict();
+
+ info("Sending FirmwareResponsePreflight now...\n");
+ restore_error = restored_send(restore, dict);
+ plist_free(dict);
+ if (restore_error != RESTORE_E_SUCCESS) {
+ error("ERROR: Couldn't send FirmwareResponsePreflight data (%d)\n", restore_error);
+ return -1;
+ }
+
+ info("Done sending FirmwareUpdaterPreflight response\n");
+ 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)
{
plist_t arguments;
@@ -2738,7 +3153,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;
@@ -2757,7 +3172,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;
@@ -2774,9 +3189,37 @@ 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) {
+ 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);
+ 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);
+ 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'.\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;
@@ -2803,6 +3246,37 @@ error_out:
return -1;
}
+static int restore_send_receipt_manifest(restored_client_t restore, struct idevicerestore_client_t* client, plist_t build_identity)
+{
+ plist_t dict;
+ int restore_error;
+
+ plist_t manifest = plist_dict_get_item(build_identity, "Manifest");
+ if (!manifest) {
+ error("failed to get Manifest node from build_identity");
+ goto error_out;
+ }
+
+ 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);
+ plist_free(dict);
+ if (restore_error != RESTORE_E_SUCCESS) {
+ error("ERROR: Couldn't send ReceiptManifest data (%d)\n", restore_error);
+ goto error_out;
+ }
+
+ info("Done sending ReceiptManifest data\n");
+
+ return 0;
+
+error_out:
+ return -1;
+}
+
+
struct cpio_odc_header {
char c_magic[6];
char c_dev[6];
@@ -2869,7 +3343,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/";
@@ -2950,24 +3424,27 @@ static int restore_send_bootability_bundle_data(restored_client_t restore, struc
return 0;
}
-plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8_t is_recover_os)
+plist_t restore_get_build_identity(struct idevicerestore_client_t* client, uint8_t is_recovery_os)
{
const char *variant;
- if (is_recover_os)
- variant = "macOS Customer";
+ if (is_recovery_os)
+ variant = RESTORE_VARIANT_MACOS_RECOVERY_OS;
else if (client->flags & FLAG_ERASE)
- variant = "Customer Erase Install (IPSW)";
+ variant = RESTORE_VARIANT_ERASE_INSTALL;
else
- variant = "Customer Upgrade Install (IPSW)";
+ variant = RESTORE_VARIANT_UPGRADE_INSTALL;
plist_t build_identity = build_manifest_get_build_identity_for_model_with_variant(
client->build_manifest,
client->device->hardware_model,
- variant);
+ 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;
}
@@ -2975,11 +3452,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");
- plist_t is_recovery_node = plist_dict_get_item(args, "IsRecoveryOS");
- uint8_t is_recovery = 0;
- plist_get_bool_val(is_recovery_node, &is_recovery);
-
- return restore_get_build_identity(client, is_recovery);
+ return restore_get_build_identity(client, plist_dict_get_bool(args, "IsRecoveryOS"));
}
int extract_macos_variant(plist_t build_identity, char** output)
@@ -3000,27 +3473,32 @@ 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)
+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);
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 NULL;
+ }
}
// The path of the global manifest is hardcoded. There's no pointer to in the build manifest.
@@ -3030,7 +3508,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");
@@ -3041,9 +3529,46 @@ int extract_global_manifest(struct idevicerestore_client_t* client, plist_t buil
return 0;
}
+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) {
+ // 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(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 > 0x1000000) {
+ 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;
+}
+
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(msg);
+ }
char *image_name = NULL;
plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName");
@@ -3064,12 +3589,11 @@ 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, &data, &size);
+ int ret = extract_global_manifest(client, build_identity, NULL, &data, &size);
if (ret != 0) {
return -1;
}
@@ -3115,7 +3639,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;
@@ -3125,49 +3649,37 @@ 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 (%" 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;
-
- 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(&rctx, (data + size - i), blob_size, size-i, 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(&rctx, NULL, 0, size-i, size);
+
+ 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, plist_t build_identity)
{
- debug_plist(msg);
+ if (idevicerestore_debug) {
+ debug("DEBUG: %s: Got SourceBootObjectV4 request:\n", __func__);
+ debug_plist(msg);
+ }
char *image_name = NULL;
plist_t node = plist_access_path(msg, 2, "Arguments", "ImageName");
@@ -3190,27 +3702,27 @@ 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) {
- int ret = extract_global_manifest(client, build_identity, &data, &size);
- if (ret != 0) {
+ 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;
}
- } 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");
+ plist_get_string_val(node, &variant);
+ if (!variant) {
+ debug("Failed to parse arguments from SourceBootObjectV4 as string\n");
return -1;
}
+
+ path = extract_global_manifest_path(build_identity, variant);
+ } else if (strcmp(image_name, "__RestoreVersion__") == 0) {
+ 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) {
@@ -3225,53 +3737,31 @@ 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;
- }
+ if (!path) {
+ error("ERROR: Failed to get path for component %s\n", component);
+ return -1;
+ }
- plist_free(dict);
+ uint64_t fsize = 0;
+ ipsw_get_file_size(client->ipsw, path, &fsize);
- i -= blob_size;
- }
- debug("\n");
+ info("Sending %s now (%" PRIu64 " bytes)\n", component, fsize);
- // Send FileDataDone
- dict = plist_new_dict();
- plist_dict_set_item(dict, "FileDataDone", plist_new_bool(1));
+ struct _restore_send_file_data_ctx rctx;
+ rctx.client = client;
+ rctx.restore = restore;
+ rctx.last_progress = 0;
- 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, &rctx) < 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;
}
@@ -3352,7 +3842,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;
@@ -3364,7 +3854,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;
}
@@ -3400,7 +3890,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;
}
@@ -3452,7 +3942,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) < 0) {
+ if(restore_send_nor(restore, client, build_identity, message) < 0) {
error("ERROR: Unable to send NOR data\n");
return -1;
}
@@ -3483,6 +3973,13 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev
}
}
+ else if (!strcmp(type, "FirmwareUpdaterPreflight")) {
+ if(restore_send_firmware_updater_preflight(restore, client, build_identity, 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) {
error("ERROR: Unable to send FirmwareUpdater data\n");
@@ -3511,6 +4008,20 @@ int restore_handle_data_request_msg(struct idevicerestore_client_t* client, idev
}
}
+ else if (!strcmp(type, "ReceiptManifest")) {
+ if (restore_send_receipt_manifest(restore, client, build_identity) < 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, device, message) < 0) {
+ error("ERROR: Unable to send BasebandUpdaterOutputData data\n");
+ return -1;
+ }
+ }
+
else {
// Unknown DataType!!
error("Unknown data request '%s' received\n", type);
@@ -3532,6 +4043,7 @@ plist_t restore_supported_data_types()
plist_dict_set_item(dict, "BootabilityBundle", plist_new_bool(0));
plist_dict_set_item(dict, "BuildIdentityDict", plist_new_bool(0));
plist_dict_set_item(dict, "BuildIdentityDictV2", plist_new_bool(0));
+ plist_dict_set_item(dict, "Cryptex1LocalPolicy", plist_new_bool(1));
plist_dict_set_item(dict, "DataType", plist_new_bool(0));
plist_dict_set_item(dict, "DiagData", plist_new_bool(0));
plist_dict_set_item(dict, "EANData", plist_new_bool(0));
@@ -3580,6 +4092,12 @@ plist_t restore_supported_data_types()
plist_dict_set_item(dict, "SystemImageRootHash", plist_new_bool(0));
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));
return dict;
}
@@ -3615,7 +4133,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;
@@ -3755,7 +4273,6 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
plist_dict_set_item(opts, "AutoBootDelay", plist_new_uint(0));
if (client->preflight_info) {
- plist_t node;
plist_t bbus = plist_copy(client->preflight_info);
plist_dict_remove_item(bbus, "FusingStatus");
@@ -3763,17 +4280,14 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
plist_dict_set_item(opts, "BBUpdaterState", bbus);
- node = plist_dict_get_item(client->preflight_info, "Nonce");
- if (node) {
- plist_dict_set_item(opts, "BasebandNonce", plist_copy(node));
- }
+ plist_dict_copy_data(opts, client->preflight_info, "BasebandNonce", "Nonce");
}
plist_dict_set_item(opts, "SupportedDataTypes", restore_supported_data_types());
plist_dict_set_item(opts, "SupportedMessageTypes", restore_supported_message_types());
// FIXME: Should be adjusted for update behaviors
- if (client->build_major >= 20) {
+ if (client->macos_variant) {
plist_dict_set_item(opts, "AddSystemPartitionPadding", plist_new_bool(1));
plist_dict_set_item(opts, "AllowUntetheredRestore", plist_new_bool(0));
plist_dict_set_item(opts, "AuthInstallEnableSso", plist_new_bool(0));
@@ -3896,7 +4410,7 @@ int restore_device(struct idevicerestore_client_t* client, plist_t build_identit
// this is the restore process loop, it reads each message in from
// restored and passes that data on to it's specific handler
while (!(client->flags & FLAG_QUIT)) {
- if (client->flags & FLAG_IGNORE_ERRORS) {
+ if (err != 0 && client->flags & FLAG_IGNORE_ERRORS) {
error("WARNING: Attempting to continue after critical error, restore might fail...\n");
err = 0;
}
@@ -3942,7 +4456,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
@@ -3971,29 +4485,45 @@ 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);
+
+ 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_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));
+ }
}
// baseband update message
diff --git a/src/restore.h b/src/restore.h
index c93e325..765f374 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_send_nor(restored_client_t restore, struct idevicerestore_client_t* client, 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 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
diff --git a/src/tss.c b/src/tss.c
index 084ad10..99781ef 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 "973.40.2"
#ifdef WIN32
#define TSS_CLIENT_VERSION_STRING "libauthinstall_Win-"AUTH_VERSION""
@@ -49,7 +49,8 @@ typedef struct {
char* content;
} tss_response;
-char* ecid_to_string(uint64_t ecid) {
+char* ecid_to_string(uint64_t ecid)
+{
char* ecid_string = malloc(ECID_STRSIZE);
memset(ecid_string, '\0', ECID_STRSIZE);
if (ecid == 0) {
@@ -60,11 +61,10 @@ char* ecid_to_string(uint64_t ecid) {
return ecid_string;
}
-plist_t tss_request_new(plist_t overrides) {
-
+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")
@@ -90,580 +90,279 @@ plist_t tss_request_new(plist_t overrides) {
int tss_request_add_local_policy_tags(plist_t request, plist_t parameters)
{
- plist_t node = NULL;
-
plist_dict_set_item(request, "@ApImg4Ticket", plist_new_bool(1));
- /* Ap,LocalBoot */
- node = plist_dict_get_item(parameters, "Ap,LocalBoot");
- if (!node || plist_get_node_type(node) != PLIST_BOOLEAN) {
+ if (plist_dict_copy_bool(request, parameters, "Ap,LocalBoot", NULL) < 0) {
error("ERROR: Unable to find required Ap,LocalBoot in parameters\n");
return -1;
}
- plist_dict_set_item(request, "Ap,LocalBoot", plist_copy(node));
- node = NULL;
- /* Ap,LocalPolicy */
- node = plist_dict_get_item(parameters, "Ap,LocalPolicy");
- if (!node || plist_get_node_type(node) != PLIST_DICT) {
+ if (plist_dict_copy_item(request, parameters, "Ap,LocalPolicy", NULL) < 0) {
error("ERROR: Unable to find required Ap,LocalPolicy in parameters\n");
return -1;
}
- plist_dict_set_item(request, "Ap,LocalPolicy", plist_copy(node));
- node = NULL;
- /* Ap,NextStageIM4MHash */
- node = plist_dict_get_item(parameters, "Ap,NextStageIM4MHash");
- if (!node || plist_get_node_type(node) != PLIST_DATA) {
+ 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_set_item(request, "Ap,NextStageIM4MHash", plist_copy(node));
- node = NULL;
-
- /* Ap,RecoveryOSPolicyNonceHash */
- node = plist_dict_get_item(parameters, "Ap,RecoveryOSPolicyNonceHash");
- if (node) {
- plist_dict_set_item(request, "Ap,RecoveryOSPolicyNonceHash", plist_copy(node));
- }
- node = NULL;
-
- /* Ap,VolumeUUID */
- node = plist_dict_get_item(parameters, "Ap,VolumeUUID");
- if (node) {
- plist_dict_set_item(request, "Ap,VolumeUUID", plist_copy(node));
- }
- node = NULL;
-
- /* ApECID */
- node = plist_dict_get_item(parameters, "ApECID");
- if (node) {
- plist_dict_set_item(request, "ApECID", plist_copy(node));
- }
- node = NULL;
-
- /* ApChipID */
- node = plist_dict_get_item(parameters, "ApChipID");
- if (node) {
- plist_dict_set_item(request, "ApChipID", plist_copy(node));
- }
- node = NULL;
- /* ApBoardID */
- node = plist_dict_get_item(parameters, "ApBoardID");
- if (node) {
- plist_dict_set_item(request, "ApBoardID", plist_copy(node));
- }
- node = NULL;
-
- /* ApSecurityDomain */
- node = plist_dict_get_item(parameters, "ApSecurityDomain");
- if (node) {
- plist_dict_set_item(request, "ApSecurityDomain", plist_copy(node));
- }
- node = NULL;
-
- /* ApNonce */
- node = plist_dict_get_item(parameters, "ApNonce");
- if (node) {
- plist_dict_set_item(request, "ApNonce", plist_copy(node));
- }
- node = 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);
- /* ApSecurityMode */
- node = plist_dict_get_item(request, "ApSecurityMode");
- if (!node) {
+ if (!plist_dict_get_item(request, "ApSecurityMode")) {
/* copy from parameters if available */
- node = plist_dict_get_item(parameters, "ApSecurityMode");
- if (!node || plist_get_node_type(node) != PLIST_BOOLEAN) {
+ if (plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) {
error("ERROR: Unable to find required ApSecurityMode in parameters\n");
return -1;
}
- plist_dict_set_item(request, "ApSecurityMode", plist_copy(node));
- node = NULL;
}
-
- node = plist_dict_get_item(request, "ApProductionMode");
- if (!node) {
- /* ApProductionMode */
- node = plist_dict_get_item(parameters, "ApProductionMode");
- if (!node || plist_get_node_type(node) != PLIST_BOOLEAN) {
+ 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;
}
- plist_dict_set_item(request, "ApProductionMode", plist_copy(node));
- node = NULL;
}
return 0;
}
-int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity)
+int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity, bool include_manifest)
{
plist_t node = NULL;
- char* string = NULL;
- /* UniqueBuildID */
- node = plist_dict_get_item(build_identity, "UniqueBuildID");
- if (!node || plist_get_node_type(node) != PLIST_DATA) {
+ if (plist_dict_copy_data(parameters, build_identity, "UniqueBuildID", NULL) < 0) {
error("ERROR: Unable to find UniqueBuildID node\n");
return -1;
}
- plist_dict_set_item(parameters, "UniqueBuildID", plist_copy(node));
- node = NULL;
- /* Ap,OSLongVersion */
- node = plist_dict_get_item(build_identity, "Ap,OSLongVersion");
- if (node) {
- plist_dict_set_item(parameters, "Ap,OSLongVersion", plist_copy(node));
- }
+ plist_dict_copy_string(parameters, build_identity, "Ap,OSLongVersion", NULL);
- /* ApChipID */
- int chip_id = 0;
- node = plist_dict_get_item(build_identity, "ApChipID");
- if (!node || plist_get_node_type(node) != PLIST_STRING) {
+ if (plist_dict_copy_uint(parameters, build_identity, "ApChipID", NULL) < 0) {;
error("ERROR: Unable to find ApChipID node\n");
return -1;
}
- plist_get_string_val(node, &string);
- sscanf(string, "%x", &chip_id);
- plist_dict_set_item(parameters, "ApChipID", plist_new_uint(chip_id));
- free(string);
- string = NULL;
- node = NULL;
- /* ApBoardID */
- int board_id = 0;
- node = plist_dict_get_item(build_identity, "ApBoardID");
- if (!node || plist_get_node_type(node) != PLIST_STRING) {
+ if (plist_dict_copy_uint(parameters, build_identity, "ApBoardID", NULL) < 0) {
error("ERROR: Unable to find ApBoardID node\n");
return -1;
}
- plist_get_string_val(node, &string);
- sscanf(string, "%x", &board_id);
- plist_dict_set_item(parameters, "ApBoardID", plist_new_uint(board_id));
- free(string);
- string = NULL;
- node = NULL;
- /* ApSecurityDomain */
- int security_domain = 0;
- node = plist_dict_get_item(build_identity, "ApSecurityDomain");
- if (!node || plist_get_node_type(node) != PLIST_STRING) {
- error("ERROR: Unable to find ApSecurityDomain node\n");
- return -1;
- }
- plist_get_string_val(node, &string);
- sscanf(string, "%x", &security_domain);
- plist_dict_set_item(parameters, "ApSecurityDomain", plist_new_uint(security_domain));
- free(string);
- string = NULL;
- node = NULL;
-
- /* BMU,BoardID */
- node = plist_dict_get_item(build_identity, "BMU,BoardID");
- if (node) {
- plist_dict_set_item(parameters, "BMU,BoardID", plist_copy(node));
- }
+ 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);
- /* BMU,ChipID */
- node = plist_dict_get_item(build_identity, "BMU,ChipID");
- if (node) {
- plist_dict_set_item(parameters, "BMU,ChipID", plist_copy(node));
- }
-
- /* BbChipID */
- int bb_chip_id = 0;
- char* bb_chip_id_string = NULL;
- node = plist_dict_get_item(build_identity, "BbChipID");
- if (node && plist_get_node_type(node) == PLIST_STRING) {
- plist_get_string_val(node, &bb_chip_id_string);
- sscanf(bb_chip_id_string, "%x", &bb_chip_id);
- plist_dict_set_item(parameters, "BbChipID", plist_new_uint(bb_chip_id));
- } else {
+ if (plist_dict_copy_uint(parameters, build_identity, "BbChipID", NULL) < 0) {
debug("NOTE: Unable to find BbChipID node\n");
}
- node = NULL;
- /* BbProvisioningManifestKeyHash */
- node = plist_dict_get_item(build_identity, "BbProvisioningManifestKeyHash");
- if (node && plist_get_node_type(node) == PLIST_DATA) {
- plist_dict_set_item(parameters, "BbProvisioningManifestKeyHash", plist_copy(node));
- } else {
+ if (plist_dict_copy_data(parameters, build_identity, "BbProvisioningManifestKeyHash", NULL) < 0) {
debug("NOTE: Unable to find BbProvisioningManifestKeyHash node\n");
}
- node = NULL;
- /* BbActivationManifestKeyHash - Used by Qualcomm MDM6610 */
- node = plist_dict_get_item(build_identity, "BbActivationManifestKeyHash");
- if (node && plist_get_node_type(node) == PLIST_DATA) {
- plist_dict_set_item(parameters, "BbActivationManifestKeyHash", plist_copy(node));
- } else {
+ if (plist_dict_copy_data(parameters, build_identity, "BbActivationManifestKeyHash", NULL) < 0) {
debug("NOTE: Unable to find BbActivationManifestKeyHash node\n");
}
- node = NULL;
- node = plist_dict_get_item(build_identity, "BbCalibrationManifestKeyHash");
- if (node && plist_get_node_type(node) == PLIST_DATA) {
- plist_dict_set_item(parameters, "BbCalibrationManifestKeyHash", plist_copy(node));
- } else {
+ if (plist_dict_copy_data(parameters, build_identity, "BbCalibrationManifestKeyHash", NULL) < 0) {
debug("NOTE: Unable to find BbCalibrationManifestKeyHash node\n");
}
- node = NULL;
- /* BbFactoryActivationManifestKeyHash */
- node = plist_dict_get_item(build_identity, "BbFactoryActivationManifestKeyHash");
- if (node && plist_get_node_type(node) == PLIST_DATA) {
- plist_dict_set_item(parameters, "BbFactoryActivationManifestKeyHash", plist_copy(node));
- } else {
+ if (plist_dict_copy_data(parameters, build_identity, "BbFactoryActivationManifestKeyHash", NULL) < 0) {
debug("NOTE: Unable to find BbFactoryActivationManifestKeyHash node\n");
}
- node = NULL;
- /* BbFDRSecurityKeyHash */
- node = plist_dict_get_item(build_identity, "BbFDRSecurityKeyHash");
- if (node && plist_get_node_type(node) == PLIST_DATA) {
- plist_dict_set_item(parameters, "BbFDRSecurityKeyHash", plist_copy(node));
- } else {
+ if (plist_dict_copy_data(parameters, build_identity, "BbFDRSecurityKeyHash", NULL) < 0) {
debug("NOTE: Unable to find BbFDRSecurityKeyHash node\n");
}
- node = NULL;
/* BbSkeyId - Used by XMM 6180/GSM */
- node = plist_dict_get_item(build_identity, "BbSkeyId");
- if (node && plist_get_node_type(node) == PLIST_DATA) {
- plist_dict_set_item(parameters, "BbSkeyId", plist_copy(node));
- } else {
+ if (plist_dict_copy_data(parameters, build_identity, "BbSkeyId", NULL) < 0) {
debug("NOTE: Unable to find BbSkeyId node\n");
}
- node = NULL;
/* SE,ChipID - Used for SE firmware request */
- node = plist_dict_get_item(build_identity, "SE,ChipID");
- if (node) {
- if (plist_get_node_type(node) == PLIST_STRING) {
- char *strval = NULL;
- int intval = 0;
- plist_get_string_val(node, &strval);
- sscanf(strval, "%x", &intval);
- plist_dict_set_item(parameters, "SE,ChipID", plist_new_uint(intval));
- } else {
- plist_dict_set_item(parameters, "SE,ChipID", plist_copy(node));
- }
- }
- node = NULL;
+ plist_dict_copy_uint(parameters, build_identity, "SE,ChipID", NULL);
/* Savage,ChipID - Used for Savage firmware request */
- node = plist_dict_get_item(build_identity, "Savage,ChipID");
- if (node) {
- if (plist_get_node_type(node) == PLIST_STRING) {
- char *strval = NULL;
- int intval = 0;
- plist_get_string_val(node, &strval);
- sscanf(strval, "%x", &intval);
- plist_dict_set_item(parameters, "Savage,ChipID", plist_new_uint(intval));
- } else {
- plist_dict_set_item(parameters, "Savage,ChipID", plist_copy(node));
- }
- }
- node = NULL;
+ plist_dict_copy_uint(parameters, build_identity, "Savage,ChipID", NULL);
/* add Savage,PatchEpoch - Used for Savage firmware request */
- node = plist_dict_get_item(build_identity, "Savage,PatchEpoch");
- if (node) {
- if (plist_get_node_type(node) == PLIST_STRING) {
- char *strval = NULL;
- int intval = 0;
- plist_get_string_val(node, &strval);
- sscanf(strval, "%x", &intval);
- plist_dict_set_item(parameters, "Savage,PatchEpoch", plist_new_uint(intval));
- } else {
- plist_dict_set_item(parameters, "Savage,PatchEpoch", plist_copy(node));
- }
- }
- node = NULL;
+ plist_dict_copy_uint(parameters, build_identity, "Savage,PatchEpoch", NULL);
/* Yonkers,BoardID - Used for Yonkers firmware request */
- node = plist_dict_get_item(build_identity, "Yonkers,BoardID");
- if (node) {
- if (plist_get_node_type(node) == PLIST_STRING) {
- char *strval = NULL;
- int intval = 0;
- plist_get_string_val(node, &strval);
- sscanf(strval, "%x", &intval);
- plist_dict_set_item(parameters, "Yonkers,BoardID", plist_new_uint(intval));
- } else {
- plist_dict_set_item(parameters, "Yonkers,BoardID", plist_copy(node));
- }
- }
- node = NULL;
+ plist_dict_copy_uint(parameters, build_identity, "Yonkers,BoardID", NULL);
/* Yonkers,ChipID - Used for Yonkers firmware request */
- node = plist_dict_get_item(build_identity, "Yonkers,ChipID");
- if (node) {
- if (plist_get_node_type(node) == PLIST_STRING) {
- char *strval = NULL;
- int intval = 0;
- plist_get_string_val(node, &strval);
- sscanf(strval, "%x", &intval);
- plist_dict_set_item(parameters, "Yonkers,ChipID", plist_new_uint(intval));
- } else {
- plist_dict_set_item(parameters, "Yonkers,ChipID", plist_copy(node));
- }
- }
- node = NULL;
+ plist_dict_copy_uint(parameters, build_identity, "Yonkers,ChipID", NULL);
/* add Yonkers,PatchEpoch - Used for Yonkers firmware request */
- node = plist_dict_get_item(build_identity, "Yonkers,PatchEpoch");
+ 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) {
- if (plist_get_node_type(node) == PLIST_STRING) {
- char *strval = NULL;
- int intval = 0;
- plist_get_string_val(node, &strval);
- sscanf(strval, "%x", &intval);
- plist_dict_set_item(parameters, "Yonkers,PatchEpoch", plist_new_uint(intval));
- } else {
- plist_dict_set_item(parameters, "Yonkers,PatchEpoch", plist_copy(node));
- }
- }
- node = NULL;
-
- /* add Rap,BoardID */
- node = plist_dict_get_item(build_identity, "Rap,BoardID");
- if (node) {
- plist_dict_set_item(parameters, "Rap,BoardID", plist_copy(node));
- }
- node = NULL;
-
- /* add Rap,ChipID */
- node = plist_dict_get_item(build_identity, "Rap,ChipID");
- if (node) {
- plist_dict_set_item(parameters, "Rap,ChipID", plist_copy(node));
- }
- node = NULL;
-
- /* add Rap,SecurityDomain */
- node = plist_dict_get_item(build_identity, "Rap,SecurityDomain");
- if (node) {
- plist_dict_set_item(parameters, "Rap,SecurityDomain", plist_copy(node));
- }
- node = NULL;
-
- /* add Baobab,BoardID */
- node = plist_dict_get_item(build_identity, "Baobab,BoardID");
- if (node) {
- plist_dict_set_item(parameters, "Baobab,BoardID", plist_copy(node));
- }
- node = NULL;
-
- /* add Baobab,ChipID */
- node = plist_dict_get_item(build_identity, "Baobab,ChipID");
- if (node) {
- plist_dict_set_item(parameters, "Baobab,ChipID", plist_copy(node));
- }
- node = NULL;
-
- /* add Baobab,ManifestEpoch */
- node = plist_dict_get_item(build_identity, "Baobab,ManifestEpoch");
- if (node) {
- plist_dict_set_item(parameters, "Baobab,ManifestEpoch", plist_copy(node));
+ plist_dict_copy_bool(parameters, node, "RequiresUIDMode", NULL);
}
- node = NULL;
- /* add Baobab,SecurityDomain */
- node = plist_dict_get_item(build_identity, "Baobab,SecurityDomain");
- if (node) {
- plist_dict_set_item(parameters, "Baobab,SecurityDomain", plist_copy(node));
- }
- node = NULL;
-
- /* add eUICC,ChipID */
- node = plist_dict_get_item(build_identity, "eUICC,ChipID");
- if (node) {
- plist_dict_set_item(parameters, "eUICC,ChipID", plist_copy(node));
- }
- node = NULL;
-
- node = plist_dict_get_item(build_identity, "PearlCertificationRootPub");
- if (node) {
- plist_dict_set_item(parameters, "PearlCertificationRootPub", plist_copy(node));
- }
- node = NULL;
-
- /* add build identity manifest dictionary */
- node = plist_dict_get_item(build_identity, "Manifest");
- if (!node || plist_get_node_type(node) != PLIST_DICT) {
- error("ERROR: Unable to find Manifest node\n");
- return -1;
+ 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));
}
- plist_dict_set_item(parameters, "Manifest", plist_copy(node));
return 0;
}
-int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters) {
- plist_t node = NULL;
-
+int tss_request_add_ap_img4_tags(plist_t request, plist_t parameters)
+{
if (!parameters) {
error("ERROR: Missing required AP parameters\n");
return -1;
}
- /* Ap,OSLongVersion */
- node = plist_dict_get_item(parameters, "Ap,OSLongVersion");
- if (node) {
- plist_dict_set_item(request, "Ap,OSLongVersion", plist_copy(node));
- }
+ plist_dict_copy_string(request, parameters, "Ap,OSLongVersion", NULL);
- /* ApNonce */
- node = plist_dict_get_item(parameters, "ApNonce");
- if (!node || plist_get_node_type(node) != PLIST_DATA) {
+ 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, "ApNonce", plist_copy(node));
- node = NULL;
plist_dict_set_item(request, "@ApImg4Ticket", plist_new_bool(1));
- /* ApSecurityMode */
- node = plist_dict_get_item(request, "ApSecurityMode");
- if (!node) {
+ if (!plist_dict_get_item(request, "ApSecurityMode")) {
/* copy from parameters if available */
- node = plist_dict_get_item(parameters, "ApSecurityMode");
- if (!node || plist_get_node_type(node) != PLIST_BOOLEAN) {
+ if (plist_dict_copy_bool(request, parameters, "ApSecurityMode", NULL) < 0) {
error("ERROR: Unable to find required ApSecurityMode in parameters\n");
return -1;
}
- plist_dict_set_item(request, "ApSecurityMode", plist_copy(node));
- node = NULL;
}
-
- node = plist_dict_get_item(request, "ApProductionMode");
- if (!node) {
+ if (!plist_dict_get_item(request, "ApProductionMode")) {
/* ApProductionMode */
- node = plist_dict_get_item(parameters, "ApProductionMode");
- if (!node || plist_get_node_type(node) != PLIST_BOOLEAN) {
+ if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) {
error("ERROR: Unable to find required ApProductionMode in parameters\n");
return -1;
}
- plist_dict_set_item(request, "ApProductionMode", plist_copy(node));
- node = NULL;
}
- /* ApSepNonce */
- node = plist_dict_get_item(parameters, "ApSepNonce");
- if (!node || plist_get_node_type(node) != PLIST_DATA) {
- error("ERROR: Unable to find required ApSepNonce 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));
}
- plist_dict_set_item(request, "SepNonce", plist_copy(node));
- node = NULL;
- /* PearlCertificationRootPub */
- node = plist_dict_get_item(parameters, "PearlCertificationRootPub");
- if (node) {
- plist_dict_set_item(request, "PearlCertificationRootPub", plist_copy(node));
+ // 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) {
- plist_t node = NULL;
-
+int tss_request_add_ap_img3_tags(plist_t request, plist_t parameters)
+{
if (!parameters) {
error("ERROR: Missing required AP parameters\n");
return -1;
}
- /* ApNonce */
- node = plist_dict_get_item(parameters, "ApNonce");
- if (node) {
- if (plist_get_node_type(node) != PLIST_DATA) {
- error("ERROR: Unable to find required ApNonce in parameters\n");
- return -1;
- }
- plist_dict_set_item(request, "ApNonce", plist_copy(node));
- node = NULL;
+ if (plist_dict_copy_data(request, parameters, "ApNonce", NULL) < 0) {
+ error("WARNING: Unable to find ApNonce in parameters\n");
}
- /* @APTicket */
plist_dict_set_item(request, "@APTicket", plist_new_bool(1));
- /* ApBoardID */
- node = plist_dict_get_item(request, "ApBoardID");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
+ if (plist_dict_copy_uint(request, parameters, "ApBoardID", NULL) < 0) {
error("ERROR: Unable to find required ApBoardID in request\n");
return -1;
}
- node = NULL;
- /* ApChipID */
- node = plist_dict_get_item(request, "ApChipID");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
+ if (plist_dict_copy_uint(request, parameters, "ApChipID", NULL) < 0) {
error("ERROR: Unable to find required ApChipID in request\n");
return -1;
}
- node = NULL;
- /* ApSecurityDomain */
- node = plist_dict_get_item(request, "ApSecurityDomain");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
+ if (plist_dict_copy_uint(request, parameters, "ApSecurityDomain", NULL) < 0) {
error("ERROR: Unable to find required ApSecurityDomain in request\n");
return -1;
}
- node = NULL;
- /* ApProductionMode */
- node = plist_dict_get_item(parameters, "ApProductionMode");
- if (!node || plist_get_node_type(node) != PLIST_BOOLEAN) {
+ if (plist_dict_copy_bool(request, parameters, "ApProductionMode", NULL) < 0) {
error("ERROR: Unable to find required ApProductionMode in parameters\n");
return -1;
}
- plist_dict_set_item(request, "ApProductionMode", plist_copy(node));
- node = NULL;
return 0;
}
-int tss_request_add_common_tags(plist_t request, plist_t parameters, plist_t overrides) {
- plist_t node = NULL;
-
- /* ApECID */
- node = plist_dict_get_item(parameters, "ApECID");
- if (node) {
- plist_dict_set_item(request, "ApECID", plist_copy(node));
- }
- node = NULL;
-
- /* UniqueBuildID */
- node = plist_dict_get_item(parameters, "UniqueBuildID");
- if (node) {
- plist_dict_set_item(request, "UniqueBuildID", plist_copy(node));
- }
- node = NULL;
-
- /* ApChipID */
- node = plist_dict_get_item(parameters, "ApChipID");
- if (node) {
- plist_dict_set_item(request, "ApChipID", plist_copy(node));
- }
- node = NULL;
-
- /* ApBoardID */
- node = plist_dict_get_item(parameters, "ApBoardID");
- if (node) {
- plist_dict_set_item(request, "ApBoardID", plist_copy(node));
- }
- node = NULL;
-
- /* ApSecurityDomain */
- node = plist_dict_get_item(parameters, "ApSecurityDomain");
- if (node) {
- plist_dict_set_item(request, "ApSecurityDomain", plist_copy(node));
- }
- node = NULL;
+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) {
@@ -750,7 +449,8 @@ static void tss_entry_apply_restore_request_rules(plist_t tss_entry, plist_t par
}
}
-int tss_request_add_ap_recovery_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)
+{
/* 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) {
@@ -876,14 +576,21 @@ 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")) {
- 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;
}
}
@@ -902,14 +609,9 @@ 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 */
- plist_t node = plist_dict_get_item(manifest_entry, "Trusted");
- if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
- uint8_t trusted;
- plist_get_bool_val(node, &trusted);
- if (trusted && !plist_access_path(manifest_entry, 1, "Digest")) {
- debug("DEBUG: No Digest data, using empty value for entry %s\n", key);
- plist_dict_set_item(tss_entry, "Digest", plist_new_data(NULL, 0));
- }
+ 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 */
@@ -926,7 +628,8 @@ int tss_request_add_ap_recovery_tags(plist_t request, plist_t parameters, plist_
return 0;
}
-int tss_request_add_ap_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)
+{
/* 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) {
@@ -976,25 +679,43 @@ 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;
}
}
- if (_plist_dict_get_bool(parameters, "_OnlyFWComponents")) {
- if (!_plist_dict_get_bool(manifest_entry, "Trusted")) {
+ 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;
}
}
+ /* 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);
@@ -1009,14 +730,9 @@ 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 */
- plist_t node = plist_dict_get_item(manifest_entry, "Trusted");
- if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
- uint8_t trusted;
- plist_get_bool_val(node, &trusted);
- if (trusted && !plist_access_path(manifest_entry, 1, "Digest")) {
- debug("DEBUG: No Digest data, using empty value for entry %s\n", key);
- plist_dict_set_item(tss_entry, "Digest", plist_new_data(NULL, 0));
- }
+ 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 */
@@ -1033,88 +749,31 @@ int tss_request_add_ap_tags(plist_t request, plist_t parameters, plist_t overrid
return 0;
}
-int tss_request_add_baseband_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)
+{
plist_t node = NULL;
- /* BbChipID */
- uint64_t bb_chip_id = _plist_dict_get_uint(parameters, "BbChipID");
- if (bb_chip_id) {
- plist_dict_set_item(request, "BbChipID", plist_new_uint(bb_chip_id));
- }
-
- /* BbProvisioningManifestKeyHash */
- node = plist_dict_get_item(parameters, "BbProvisioningManifestKeyHash");
- if (node) {
- plist_dict_set_item(request, "BbProvisioningManifestKeyHash", plist_copy(node));
- }
- 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 */
- node = plist_dict_get_item(parameters, "BbActivationManifestKeyHash");
- if (node) {
- plist_dict_set_item(request, "BbActivationManifestKeyHash", plist_copy(node));
- }
- node = NULL;
-
- node = plist_dict_get_item(parameters, "BbCalibrationManifestKeyHash");
- if (node) {
- plist_dict_set_item(request, "BbCalibrationManifestKeyHash", plist_copy(node));
- }
- node = NULL;
-
- /* BbFactoryActivationManifestKeyHash */
- node = plist_dict_get_item(parameters, "BbFactoryActivationManifestKeyHash");
- if (node) {
- plist_dict_set_item(request, "BbFactoryActivationManifestKeyHash", plist_copy(node));
- }
- node = NULL;
-
- /* BbFDRSecurityKeyHash */
- node = plist_dict_get_item(parameters, "BbFDRSecurityKeyHash");
- if (node) {
- plist_dict_set_item(request, "BbFDRSecurityKeyHash", plist_copy(node));
- }
- node = 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 */
- node = plist_dict_get_item(parameters, "BbSkeyId");
- if (node) {
- plist_dict_set_item(request, "BbSkeyId", plist_copy(node));
- }
- node = 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);
- /* BbNonce */
- node = plist_dict_get_item(parameters, "BbNonce");
- if (node) {
- plist_dict_set_item(request, "BbNonce", plist_copy(node));
- }
- node = NULL;
-
- /* @BBTicket */
- plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
+ uint64_t bb_chip_id = plist_dict_get_uint(request, "BbChipID");
+ int32_t bb_cert_id = (int32_t)plist_dict_get_uint(request, "BbGoldCertId");
- /* BbGoldCertId */
- node = plist_dict_get_item(parameters, "BbGoldCertId");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
- error("ERROR: Unable to find required BbGoldCertId in parameters\n");
- return -1;
- }
- node = plist_copy(node);
- uint64_t val;
- plist_get_uint_val(node, &val);
- int32_t bb_cert_id = (int32_t)val;
- plist_set_uint_val(node, bb_cert_id);
- plist_dict_set_item(request, "BbGoldCertId", node);
- node = NULL;
-
- /* BbSNUM */
- node = plist_dict_get_item(parameters, "BbSNUM");
- if (!node || plist_get_node_type(node) != PLIST_DATA) {
+ if (plist_dict_copy_data(request, parameters, "BbSNUM", NULL) < 0) {
error("ERROR: Unable to find required BbSNUM in parameters\n");
return -1;
}
- plist_dict_set_item(request, "BbSNUM", plist_copy(node));
- node = NULL;
/* BasebandFirmware */
node = plist_access_path(parameters, 2, "Manifest", "BasebandFirmware");
@@ -1151,60 +810,36 @@ int tss_request_add_baseband_tags(plist_t request, plist_t parameters, plist_t o
int tss_request_add_se_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 SE,Ticket */
plist_dict_set_item(request, "@BBTicket", plist_new_bool(1));
- plist_dict_set_item(request, "@SE,Ticket", plist_new_bool(1));
- /* add SE,ChipID */
- node = plist_dict_get_item(parameters, "SE,ChipID");
- if (!node || plist_get_node_type(node) != PLIST_UINT) {
+ 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;
}
- plist_dict_set_item(request, "SE,ChipID", plist_copy(node));
- node = NULL;
- /* add SE,ID */
- node = plist_dict_get_item(parameters, "SE,ID");
- if (!node) {
+ 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;
}
- plist_dict_set_item(request, "SE,ID", plist_copy(node));
- node = NULL;
- /* add SE,Nonce */
- node = plist_dict_get_item(parameters, "SE,Nonce");
- if (!node) {
+ 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;
}
- plist_dict_set_item(request, "SE,Nonce", plist_copy(node));
- node = NULL;
- /* add SE,RootKeyIdentifier */
- node = plist_dict_get_item(parameters, "SE,RootKeyIdentifier");
- if (!node) {
+ 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;
}
- plist_dict_set_item(request, "SE,RootKeyIdentifier", plist_copy(node));
- node = NULL;
/* 'IsDev' determines whether we have Production or Development */
- uint8_t is_dev = 0;
- node = plist_dict_get_item(parameters, "SE,IsDev");
- if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
- plist_get_bool_val(node, &is_dev);
- }
+ uint8_t is_dev = plist_dict_get_bool(parameters, "SE,IsDev");
/* add SE,* components from build manifest to request */
char* key = NULL;
@@ -1257,6 +892,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;
}
@@ -1274,14 +914,10 @@ 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));
- /* add Savage,UID */
- node = plist_dict_get_item(parameters, "Savage,UID");
- if (!node) {
+ 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;
}
- plist_dict_set_item(request, "Savage,UID", plist_copy(node));
- node = NULL;
/* add SEP */
node = plist_access_path(manifest_node, 2, "SEP", "Digest");
@@ -1293,61 +929,40 @@ 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);
- /* add Savage,PatchEpoch */
- node = plist_dict_get_item(parameters, "Savage,PatchEpoch");
- if (!node) {
+ 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;
}
- plist_dict_set_item(request, "Savage,PatchEpoch", plist_copy(node));
- node = NULL;
- /* add Savage,ChipID */
- node = plist_dict_get_item(parameters, "Savage,ChipID");
- if (!node) {
+ 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;
}
- plist_dict_set_item(request, "Savage,ChipID", plist_copy(node));
- node = NULL;
- /* add Savage,AllowOfflineBoot */
- node = plist_dict_get_item(parameters, "Savage,AllowOfflineBoot");
- if (!node) {
+ 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;
}
- plist_dict_set_item(request, "Savage,AllowOfflineBoot", plist_copy(node));
- node = NULL;
- /* add Savage,ReadFWKey */
- node = plist_dict_get_item(parameters, "Savage,ReadFWKey");
- if (!node) {
+ 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;
}
- plist_dict_set_item(request, "Savage,ReadFWKey", plist_copy(node));
- node = NULL;
- /* add Savage,ProductionMode */
- node = plist_dict_get_item(parameters, "Savage,ProductionMode");
- if (!node) {
+ 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;
}
- plist_dict_set_item(request, "Savage,ProductionMode", plist_copy(node));
+
const char *comp_name = NULL;
- uint8_t isprod = 0;
- plist_get_bool_val(node, &isprod);
- node = NULL;
+ 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)) {
- unsigned char *savage_rev = NULL;
uint64_t savage_rev_len = 0;
- plist_get_data_val(node, (char**)&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";
@@ -1355,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 */
@@ -1372,23 +986,15 @@ int tss_request_add_savage_tags(plist_t request, plist_t parameters, plist_t ove
*component_name = strdup(comp_name);
}
- /* add Savage,Nonce */
- node = plist_dict_get_item(parameters, "Savage,Nonce");
- if (!node) {
+ 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;
}
- plist_dict_set_item(request, "Savage,Nonce", plist_copy(node));
- node = NULL;
- /* add Savage,ReadECKey */
- node = plist_dict_get_item(parameters, "Savage,ReadECKey");
- if (!node) {
+ 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;
}
- plist_dict_set_item(request, "Savage,ReadECKey", plist_copy(node));
- node = NULL;
/* apply overrides */
if (overrides) {
@@ -1437,18 +1043,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 = 1;
- uint64_t fabrevision = (uint64_t)-1;
-
- node = plist_dict_get_item(parameters, "Yonkers,ProductionMode");
- if (node && (plist_get_node_type(node) == PLIST_BOOLEAN)) {
- plist_get_bool_val(node, &isprod);
- }
-
- node = plist_dict_get_item(parameters, "Yonkers,FabRevision");
- if (node && (plist_get_node_type(node) == PLIST_UINT)) {
- plist_get_uint_val(node, &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);
@@ -1522,17 +1118,27 @@ 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));
- node = plist_dict_get_item(parameters, "eUICC,ChipID");
- if (node) {
- plist_dict_set_item(request, "eUICC,ChipID", plist_copy(node));
- }
- node = plist_dict_get_item(parameters, "eUICC,EID");
- if (node) {
- plist_dict_set_item(request, "eUICC,EID", plist_copy(node));
+ 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);
+ }
}
- node = plist_dict_get_item(parameters, "eUICC,RootKeyIdentifier");
- if (node) {
- plist_dict_set_item(request, "eUICC,RootKeyIdentifier", plist_copy(node));
+
+ 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 */
@@ -1575,31 +1181,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));
- uint64_t u64val = 0;
- uint8_t bval = 0;
-
- u64val = _plist_dict_get_uint(parameters, "Rap,BoardID");
- plist_dict_set_item(request, "Rap,BoardID", plist_new_uint(u64val));
-
- u64val = _plist_dict_get_uint(parameters, "Rap,ChipID");
- plist_dict_set_item(request, "Rap,ChipID", plist_new_uint(u64val));
-
- u64val = _plist_dict_get_uint(parameters, "Rap,ECID");
- plist_dict_set_item(request, "Rap,ECID", plist_new_uint(u64val));
-
- node = plist_dict_get_item(parameters, "Rap,Nonce");
- if (node) {
- plist_dict_set_item(request, "Rap,Nonce", plist_copy(node));
- }
-
- bval = _plist_dict_get_bool(parameters, "Rap,ProductionMode");
- plist_dict_set_item(request, "Rap,ProductionMode", plist_new_bool(bval));
-
- u64val = _plist_dict_get_uint(parameters, "Rap,SecurityDomain");
- plist_dict_set_item(request, "Rap,SecurityDomain", plist_new_uint(u64val));
-
- bval = _plist_dict_get_bool(parameters, "Rap,SecurityMode");
- plist_dict_set_item(request, "Rap,SecurityMode", plist_new_bool(bval));
+ 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;
@@ -1623,14 +1212,9 @@ 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 */
- plist_t node = plist_dict_get_item(manifest_entry, "Trusted");
- if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
- uint8_t trusted;
- plist_get_bool_val(node, &trusted);
- if (trusted && !plist_access_path(manifest_entry, 1, "Digest")) {
- debug("DEBUG: No Digest data, using empty value for entry %s\n", comp_name);
- plist_dict_set_item(manifest_entry, "Digest", plist_new_data(NULL, 0));
- }
+ 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");
@@ -1664,25 +1248,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));
- uint64_t u64val = 0;
- uint8_t bval = 0;
-
- u64val = _plist_dict_get_uint(parameters, "BMU,BoardID");
- plist_dict_set_item(request, "BMU,BoardID", plist_new_uint(u64val));
-
- u64val = _plist_dict_get_uint(parameters, "ChipID");
- plist_dict_set_item(request, "BMU,ChipID", plist_new_uint(u64val));
-
- node = plist_dict_get_item(parameters, "Nonce");
- if (node) {
- plist_dict_set_item(request, "BMU,Nonce", plist_copy(node));
- }
-
- bval = _plist_dict_get_bool(parameters, "ProductionMode");
- plist_dict_set_item(request, "BMU,ProductionMode", plist_new_bool(bval));
-
- u64val = _plist_dict_get_uint(parameters, "UniqueID");
- plist_dict_set_item(request, "BMU,UniqueID", plist_new_uint(u64val));
+ 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;
@@ -1706,14 +1276,9 @@ 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 */
- plist_t node = plist_dict_get_item(manifest_entry, "Trusted");
- if (node && plist_get_node_type(node) == PLIST_BOOLEAN) {
- uint8_t trusted;
- plist_get_bool_val(node, &trusted);
- if (trusted && !plist_access_path(manifest_entry, 1, "Digest")) {
- debug("DEBUG: No Digest data, using empty value for entry %s\n", comp_name);
- plist_dict_set_item(manifest_entry, "Digest", plist_new_data(NULL, 0));
- }
+ 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");
@@ -1747,37 +1312,94 @@ 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));
- uint64_t u64val = 0;
- uint8_t bval = 0;
- uint8_t isprod = 0;
+ 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);
- u64val = _plist_dict_get_uint(parameters, "Baobab,BoardID");
- plist_dict_set_item(request, "Baobab,BoardID", plist_new_uint(u64val));
+ uint8_t isprod = plist_dict_get_bool(parameters, "Baobab,ProductionMode");
- u64val = _plist_dict_get_uint(parameters, "Baobab,ChipID");
- plist_dict_set_item(request, "Baobab,ChipID", plist_new_uint(u64val));
+ 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);
- node = plist_dict_get_item(parameters, "Baobab,ECID");
- if (node) {
- plist_dict_set_item(request, "Baobab,ECID", 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);
- u64val = _plist_dict_get_uint(parameters, "Baobab,Life");
- plist_dict_set_item(request, "Baobab,Life", plist_new_uint(u64val));
+ /* apply overrides */
+ if (overrides) {
+ plist_dict_merge(&request, overrides);
+ }
+ return 0;
+}
- u64val = _plist_dict_get_uint(parameters, "Baobab,ManifestEpoch");
- plist_dict_set_item(request, "Baobab,ManifestEpoch", plist_new_uint(u64val));
+int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t overrides)
+{
+ plist_t node = NULL;
+ uint32_t tag = 0;
- isprod = _plist_dict_get_bool(parameters, "Baobab,ProductionMode");
- plist_dict_set_item(request, "Baobab,ProductionMode", plist_new_bool(isprod));
+ 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;
+ }
- u64val = _plist_dict_get_uint(parameters, "Baobab,SecurityDomain");
- plist_dict_set_item(request, "Baobab,SecurityDomain", plist_new_uint(u64val));
+ /* 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, "Baobab,UpdateNonce");
- if (node) {
- plist_dict_set_item(request, "Baobab,UpdateNonce", plist_copy(node));
+ 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;
@@ -1790,11 +1412,23 @@ int tss_request_add_tcon_tags(plist_t request, plist_t parameters, plist_t overr
node = NULL;
break;
}
- if (strncmp(comp_name, "Baobab,", 7) == 0) {
+ 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");
- 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);
@@ -1807,10 +1441,50 @@ int tss_request_add_tcon_tags(plist_t request, plist_t parameters, plist_t overr
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) {
+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);
@@ -1822,8 +1496,8 @@ static size_t tss_write_callback(char* data, size_t size, size_t nmemb, tss_resp
return total;
}
-plist_t tss_request_send(plist_t tss_request, const char* server_url_string) {
-
+plist_t tss_request_send(plist_t tss_request, const char* server_url_string)
+{
if (idevicerestore_debug) {
debug_plist(tss_request);
}
@@ -1882,6 +1556,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]);
@@ -1974,15 +1649,15 @@ plist_t tss_request_send(plist_t tss_request, const char* server_url_string) {
return tss_response;
}
-static int tss_response_get_data_by_key(plist_t response, const char* name, unsigned char** buffer, unsigned int* length) {
-
+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;
+ char* data = NULL;
uint64_t len = 0;
plist_get_data_val(node, &data, &len);
if (data) {
@@ -1995,19 +1670,23 @@ static int tss_response_get_data_by_key(plist_t response, const char* name, unsi
}
}
-int tss_response_get_ap_img4_ticket(plist_t response, unsigned char** ticket, unsigned int* length) {
+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) {
+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) {
+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) {
+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;
@@ -2031,7 +1710,8 @@ int tss_response_get_path_by_entry(plist_t response, const char* entry, char** p
return 0;
}
-int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char** blob) {
+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;
@@ -2087,7 +1767,8 @@ int tss_response_get_blob_by_path(plist_t tss, const char* path, unsigned char**
return 0;
}
-int tss_response_get_blob_by_entry(plist_t response, const char* entry, unsigned char** blob) {
+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;
diff --git a/src/tss.h b/src/tss.h
index 3590aed..8af2fcc 100644
--- a/src/tss.h
+++ b/src/tss.h
@@ -29,9 +29,10 @@ extern "C" {
#endif
#include <plist/plist.h>
+#include <stdbool.h>
/* parameters */
-int tss_parameters_add_from_manifest(plist_t parameters, plist_t build_identity);
+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);
@@ -48,6 +49,8 @@ int tss_request_add_vinyl_tags(plist_t request, plist_t parameters, plist_t over
int tss_request_add_rose_tags(plist_t request, plist_t parameters, plist_t overrides);
int tss_request_add_veridian_tags(plist_t request, plist_t parameters, plist_t overrides);
int tss_request_add_tcon_tags(plist_t request, plist_t parameters, plist_t overrides);
+int tss_request_add_timer_tags(plist_t request, plist_t parameters, plist_t overrides);
+int tss_request_add_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);