Skip to content

Commit a4f5a0c

Browse files
committed
img4: Add support for stitching with additional TBM data
1 parent aa98e76 commit a4f5a0c

File tree

3 files changed

+191
-7
lines changed

3 files changed

+191
-7
lines changed

src/idevicerestore.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2566,9 +2566,9 @@ int personalize_component(const char *component_name, const unsigned char* compo
25662566
unsigned char* stitched_component = NULL;
25672567
unsigned int stitched_component_size = 0;
25682568

2569-
if (tss_response && tss_response_get_ap_img4_ticket(tss_response, &component_blob, &component_blob_size) == 0) {
2569+
if (tss_response && plist_dict_get_item(tss_response, "ApImg4Ticket")) {
25702570
/* stitch ApImg4Ticket into IMG4 file */
2571-
img4_stitch_component(component_name, component_data, component_size, component_blob, component_blob_size, &stitched_component, &stitched_component_size);
2571+
img4_stitch_component(component_name, component_data, component_size, tss_response, &stitched_component, &stitched_component_size);
25722572
} else {
25732573
/* try to get blob for current component from tss response */
25742574
if (tss_response && tss_response_get_blob_by_entry(tss_response, component_name, &component_blob) < 0) {

src/img4.c

Lines changed: 188 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include "common.h"
2626
#include "img4.h"
27+
#include "tss.h"
2728

2829
#define ASN1_PRIVATE 0xc0
2930
#define ASN1_PRIMITIVE_TAG 0x1f
@@ -201,7 +202,7 @@ static void asn1_write_element(unsigned char **p, unsigned int *length, unsigned
201202
}
202203
} break;
203204
default:
204-
fprintf(stderr, "ERROR: %s: type %02x is not implemented", __func__, type);
205+
fprintf(stderr, "ERROR: %s: type %02x is not implemented\n", __func__, type);
205206
return;
206207
}
207208
}
@@ -393,7 +394,38 @@ static const char *_img4_get_component_tag(const char *compname)
393394
return NULL;
394395
}
395396

396-
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)
397+
static void hexdump(char* data, int length)
398+
{
399+
int i;
400+
int j;
401+
unsigned char c;
402+
403+
for (i = 0; i < length; i += 16) {
404+
fprintf(stderr, "%04x: ", i);
405+
for (j = 0; j < 16; j++) {
406+
if (i + j >= length) {
407+
fprintf(stderr, " ");
408+
continue;
409+
}
410+
fprintf(stderr, "%02x ", *(data + i + j) & 0xff);
411+
}
412+
fprintf(stderr, " | ");
413+
for (j = 0; j < 16; j++) {
414+
if (i + j >= length)
415+
break;
416+
c = *(data + i + j);
417+
if ((c < 32) || (c > 127)) {
418+
fprintf(stderr, ".");
419+
continue;
420+
}
421+
fprintf(stderr, "%c", c);
422+
}
423+
fprintf(stderr, "\n");
424+
}
425+
fprintf(stderr, "\n");
426+
}
427+
428+
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)
397429
{
398430
unsigned char* magic_header = NULL;
399431
unsigned int magic_header_size = 0;
@@ -404,8 +436,15 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo
404436
unsigned int content_size;
405437
unsigned char* outbuf;
406438
unsigned char* p;
439+
unsigned char* blob = NULL;
440+
unsigned int blob_size = 0;
407441

408-
if (!component_name || !component_data || component_size == 0 || !blob || blob_size == 0 || !img4_data || !img4_size) {
442+
if (!component_name || !component_data || component_size == 0 || !tss_response || !img4_data || !img4_size) {
443+
return -1;
444+
}
445+
446+
if (tss_response_get_ap_img4_ticket(tss_response, &blob, &blob_size) != 0) {
447+
error("ERROR: %s: Failed to get ApImg4Ticket from TSS response\n", __func__);
409448
return -1;
410449
}
411450

@@ -435,13 +474,152 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo
435474
}
436475
}
437476

477+
// check if we have a *-TBM entry for the given component
478+
unsigned char *additional_data = NULL;
479+
unsigned int additional_size = 0;
480+
char *tbm_key = malloc(strlen(component_name) + 5);
481+
sprintf(tbm_key, "%s-TBM", component_name);
482+
plist_t tbm_dict = plist_dict_get_item(tss_response, tbm_key);
483+
free(tbm_key);
484+
if (tbm_dict) {
485+
plist_t dt = plist_dict_get_item(tbm_dict, "ucon");
486+
if (!dt) {
487+
error("ERROR: %s: Missing ucon node in %s-TBM dictionary\n", __func__, component_name);
488+
return -1;
489+
}
490+
uint64_t ucon_size = 0;
491+
const char* ucon_data = plist_get_data_ptr(dt, &ucon_size);
492+
if (!ucon_data) {
493+
error("ERROR: %s: Missing ucon data in %s-TBM dictionary\n", __func__, component_name);
494+
return -1;
495+
}
496+
dt = plist_dict_get_item(tbm_dict, "ucer");
497+
if (!dt) {
498+
error("ERROR: %s: Missing ucer data node in %s-TBM dictionary\n", __func__, component_name);
499+
return -1;
500+
}
501+
uint64_t ucer_size = 0;
502+
const char* ucer_data = plist_get_data_ptr(dt, &ucer_size);
503+
if (!ucer_data) {
504+
error("ERROR: %s: Missing ucer data in %s-TBM dictionary\n", __func__, component_name);
505+
return -1;
506+
}
507+
508+
unsigned char *im4rset = (unsigned char*)malloc(16 + 8 + 8 + ucon_size + 16 + 8 + 8 + ucer_size + 16);
509+
unsigned char *p_im4rset = im4rset;
510+
unsigned int im4rlen = 0;
511+
512+
// ----------- ucon ------------
513+
// write priv ucon element
514+
asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"nocu");
515+
516+
// write ucon IA5STRING and ucon data
517+
unsigned char ucon_seq[16];
518+
unsigned char *p_ucon_seq = &ucon_seq[0];
519+
unsigned int ucon_seq_hdr_len = 0;
520+
asn1_write_element(&p_ucon_seq, &ucon_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucon", -1);
521+
asn1_write_element_header(ASN1_OCTET_STRING, ucon_size, &p_ucon_seq, &ucon_seq_hdr_len);
522+
523+
// write ucon sequence
524+
unsigned char elem_seq[8];
525+
unsigned char *p = &elem_seq[0];
526+
unsigned int seq_hdr_len = 0;
527+
asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, ucon_seq_hdr_len + ucon_size, &p, &seq_hdr_len);
528+
529+
// add size to priv ucon element
530+
asn1_write_size(ucon_seq_hdr_len + ucon_size + seq_hdr_len, &p_im4rset, &im4rlen);
531+
532+
// put it together
533+
memcpy(p_im4rset, elem_seq, seq_hdr_len);
534+
p_im4rset += seq_hdr_len;
535+
im4rlen += seq_hdr_len;
536+
memcpy(p_im4rset, ucon_seq, ucon_seq_hdr_len);
537+
p_im4rset += ucon_seq_hdr_len;
538+
im4rlen += ucon_seq_hdr_len;
539+
memcpy(p_im4rset, ucon_data, ucon_size);
540+
p_im4rset += ucon_size;
541+
im4rlen += ucon_size;
542+
543+
// ----------- ucer ------------
544+
// write priv ucer element
545+
asn1_write_priv_element(&p_im4rset, &im4rlen, *(uint32_t*)"recu");
546+
547+
// write ucon IA5STRING and ucer data
548+
unsigned char ucer_seq[16];
549+
unsigned char *p_ucer_seq = &ucer_seq[0];
550+
unsigned int ucer_seq_hdr_len = 0;
551+
asn1_write_element(&p_ucer_seq, &ucer_seq_hdr_len, ASN1_IA5_STRING, (void*)"ucer", -1);
552+
asn1_write_element_header(ASN1_OCTET_STRING, ucer_size, &p_ucer_seq, &ucer_seq_hdr_len);
553+
554+
p = &elem_seq[0];
555+
seq_hdr_len = 0;
556+
asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, ucer_seq_hdr_len + ucer_size, &p, &seq_hdr_len);
557+
558+
// add size to priv ucer element
559+
asn1_write_size(ucer_seq_hdr_len + ucer_size + seq_hdr_len, &p_im4rset, &im4rlen);
560+
561+
// put it together
562+
memcpy(p_im4rset, elem_seq, seq_hdr_len);
563+
p_im4rset += seq_hdr_len;
564+
im4rlen += seq_hdr_len;
565+
memcpy(p_im4rset, ucer_seq, ucer_seq_hdr_len);
566+
p_im4rset += ucer_seq_hdr_len;
567+
im4rlen += ucer_seq_hdr_len;
568+
memcpy(p_im4rset, ucer_data, ucer_size);
569+
p_im4rset += ucer_size;
570+
im4rlen += ucer_size;
571+
572+
// now construct IM4R
573+
574+
/* write inner set */
575+
unsigned char inner_set_[8];
576+
unsigned char *inner_set = &inner_set_[0];
577+
unsigned int inner_set_len = 0;
578+
asn1_write_element_header(ASN1_SET | ASN1_CONSTRUCTED, im4rlen, &inner_set, &inner_set_len);
579+
580+
/* write header values */
581+
unsigned char hdrdata_[16];
582+
unsigned char *hdrdata = &hdrdata_[0];
583+
unsigned int hdrdata_len = 0;
584+
asn1_write_element(&hdrdata, &hdrdata_len, ASN1_IA5_STRING, (void*)"IM4R", -1);
585+
586+
/* write sequence now that we know the entire size */
587+
unsigned char seq_[8];
588+
unsigned char *seq = &seq_[0];
589+
unsigned int seq_len = 0;
590+
asn1_write_element_header(ASN1_SEQUENCE | ASN1_CONSTRUCTED, im4rlen + inner_set_len + hdrdata_len, &seq, &seq_len);
591+
592+
/* write outer cont[1] */
593+
unsigned char cont_[8];
594+
unsigned char *cont = &cont_[0];
595+
unsigned int cont_len = 0;
596+
asn1_write_element_header(ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1, im4rlen + inner_set_len + hdrdata_len + seq_len, &cont, &cont_len);
597+
598+
// now put everything together
599+
additional_data = malloc(im4rlen + inner_set_len + hdrdata_len + seq_len + cont_len);
600+
p = additional_data;
601+
memcpy(p, cont_, cont_len);
602+
p += cont_len;
603+
memcpy(p, seq_, seq_len);
604+
p += seq_len;
605+
memcpy(p, hdrdata_, hdrdata_len);
606+
p += hdrdata_len;
607+
memcpy(p, inner_set_, inner_set_len);
608+
p += inner_set_len;
609+
memcpy(p, im4rset, im4rlen);
610+
p += im4rlen;
611+
additional_size = (unsigned int)(p - additional_data);
612+
613+
free(im4rset);
614+
}
615+
438616
// create element header for the "IMG4" magic
439617
asn1_create_element_header(ASN1_IA5_STRING, IMG4_MAGIC_SIZE, &magic_header, &magic_header_size);
440618
// create element header for the blob (ApImg4Ticket)
441619
asn1_create_element_header(ASN1_CONTEXT_SPECIFIC|ASN1_CONSTRUCTED, blob_size, &blob_header, &blob_header_size);
442620

443621
// calculate the size for the final IMG4 file (asn1 sequence)
444-
content_size = magic_header_size + IMG4_MAGIC_SIZE + component_size + blob_header_size + blob_size;
622+
content_size = magic_header_size + IMG4_MAGIC_SIZE + component_size + blob_header_size + blob_size + additional_size;
445623

446624
// create element header for the final IMG4 asn1 blob
447625
asn1_create_element_header(ASN1_SEQUENCE|ASN1_CONSTRUCTED, content_size, &img4header, &img4header_size);
@@ -457,6 +635,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo
457635
if (img4header) {
458636
free(img4header);
459637
}
638+
free(additional_data);
460639
error("ERROR: out of memory when personalizing IMG4 component %s\n", component_name);
461640
return -1;
462641
}
@@ -475,6 +654,10 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo
475654
p += blob_header_size;
476655
memcpy(p, blob, blob_size);
477656
p += blob_size;
657+
if (additional_size) {
658+
memcpy(p, additional_data, additional_size);
659+
p += additional_size;
660+
}
478661

479662
*img4_data = outbuf;
480663
*img4_size = (p - outbuf);
@@ -488,6 +671,7 @@ int img4_stitch_component(const char* component_name, const unsigned char* compo
488671
if (img4header) {
489672
free(img4header);
490673
}
674+
free(additional_data);
491675

492676
return 0;
493677
}

src/img4.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
extern "C" {
2727
#endif
2828

29-
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);
29+
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);
3030
int img4_create_local_manifest(plist_t request, plist_t build_identity, plist_t* manifest);
3131

3232
#ifdef __cplusplus

0 commit comments

Comments
 (0)