/* * img4.c * Functions for handling the new IMG4 format * * 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 #include #include "common.h" #include "img4.h" #define ASN1_CONSTRUCTED 0x20 #define ASN1_SEQUENCE 0x10 #define ASN1_CONTEXT_SPECIFIC 0x80 #define ASN1_IA5_STRING 0x16 #define IMG4_MAGIC "IMG4" #define IMG4_MAGIC_SIZE 4 static unsigned char* asn1_create_element_header(unsigned char type, unsigned int size, unsigned char** data, unsigned int *data_size) { unsigned char buf[6]; unsigned int off = 0; if (!type || size == 0 || !data || !data_size) { return NULL; } buf[off++] = type; // first, calculate the size if (size >= 0x1000000) { // 1+4 bytes length buf[off++] = 0x84; buf[off++] = (size >> 24) & 0xFF; buf[off++] = (size >> 16) & 0xFF; buf[off++] = (size >> 8) & 0xFF; buf[off++] = size & 0xFF; } else if (size >= 0x10000) { // 1+3 bytes length buf[off++] = 0x83; buf[off++] = (size >> 16) & 0xFF; buf[off++] = (size >> 8) & 0xFF; buf[off++] = size & 0xFF; } else if (size >= 0x100) { // 1+2 bytes length buf[off++] = 0x82; buf[off++] = (size >> 8) & 0xFF; buf[off++] = (size & 0xFF); } else if (size >= 0x80) { // 1+1 byte length buf[off++] = 0x81; buf[off++] = (size & 0xFF); } else { // 1 byte length buf[off++] = size & 0xFF; } *data = malloc(off); memcpy(*data, buf, off); *data_size = off; return *data; } 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) { unsigned char* magic_header = NULL; unsigned int magic_header_size = 0; unsigned char* blob_header = NULL; unsigned int blob_header_size = 0; unsigned char* img4header = NULL; unsigned int img4header_size = 0; unsigned int content_size; unsigned char* outbuf; unsigned char* p; if (!component_name || !component_data || component_size == 0 || !blob || blob_size == 0 || !img4_data || !img4_size) { return -1; } info("Personalizing IMG4 component %s...\n", component_name); /* first we need check if we have to change the tag for the given component */ // FIXME: write proper ASN1 handling code for this if (strcmp(component_name, "RestoreKernelCache") == 0) { memcpy((char*)component_data+0xD, "rkrn", 4); } else if (strcmp(component_name, "RestoreDeviceTree") == 0) { memcpy((char*)component_data+0xD, "rdtr", 4); } else if (strcmp(component_name, "RestoreSEP") == 0) { memcpy((char*)component_data+0xD, "rsep", 4); } // 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; // create element header for the final IMG4 asn1 blob asn1_create_element_header(ASN1_SEQUENCE|ASN1_CONSTRUCTED, content_size, &img4header, &img4header_size); outbuf = (unsigned char*)malloc(img4header_size + content_size); if (!outbuf) { if (magic_header) { free(magic_header); } if (blob_header) { free(blob_header); } if (img4header) { free(img4header); } error("ERROR: out of memory when personalizing IMG4 component %s\n", component_name); return -1; } p = outbuf; // now put everything together memcpy(p, img4header, img4header_size); p += img4header_size; memcpy(p, magic_header, magic_header_size); p += magic_header_size; memcpy(p, IMG4_MAGIC, IMG4_MAGIC_SIZE); p += IMG4_MAGIC_SIZE; memcpy(p, component_data, component_size); p += component_size; memcpy(p, blob_header, blob_header_size); p += blob_header_size; memcpy(p, blob, blob_size); p += blob_size; *img4_data = outbuf; *img4_size = (p - outbuf); if (magic_header) { free(magic_header); } if (blob_header) { free(blob_header); } if (img4header) { free(img4header); } return 0; }