/* * Copyright (C) 2009 Apple, Inc. All rights reserved. * * This document is the property of Apple Inc. * It is considered confidential and proprietary. * * This document may not be reproduced or transmitted in any form, * in whole or in part, without the express written permission of * Apple Inc. */ #include #include #include "Buffer.h" extern "C" { #include "drivers/sha1.h" #include "lib/image/image3/Image3.h" #include "lib/image/image3/Image3Format.h" #if BOOTX2BIN_WITH_IMAGE4 # include # include # include #endif }; extern "C" int image3_load(struct image_info *image_info, u_int32_t type, void **load_addr, size_t *load_len); void Buffer::alloc(size_t size) { free(); _buf = new char[size]; _size = size; memset(_buf, 0, _size); } void Buffer::free() { delete[] _buf; _buf = NULL; _size = 0; } void Buffer::swap(Buffer *other) { std::swap(_buf, other->_buf); std::swap(_size, other->_size); } void Buffer::crop(size_t newSize) { assert(newSize <= _size); _size = newSize; } bool Buffer::loadFromFile(const char *file) { // Load the contents of a file into a Buffer and return it. FILE *str = fopen(file, "rb"); if (!str) { fprintf(stderr, "Couldn't open \"%s\"\n", file); return false; } fseek(str, 0, SEEK_END); size_t size = ftell(str); fseek(str, 0, SEEK_SET); Buffer file_buf; file_buf.alloc(size); int got = fread(file_buf.buf(), file_buf.size(), 1, str); fclose(str); if (got != 1) { fprintf(stderr, "Error reading \"%s\"\n", file); return false; } file_buf.swap(this); return true; } #if BOOTX2BIN_WITH_IMAGE4 bool Buffer::loadFromIm4p(const char *file, uint32_t type, bool quiet) { // Load a payload of expected 'type' from 'file', which is in im4p // format. Returns a Buffer containing the payload. Buffer image_buf; if (!image_buf.loadFromFile(file)) { fprintf(stderr, "Couldn't load file \"%s\"\n", file); return false; } // Decode IM4P DER format. DERItem im4p; im4p.data = (DERByte *) image_buf.buf(); im4p.length = image_buf.size(); DERReturn ret; DERImg4Payload decoded; memset(&decoded, 0, sizeof(decoded)); ret = DERImg4DecodePayload(&im4p, &decoded); if (ret != DR_Success) { // This isn't a .im4p if (!quiet) fprintf(stderr, "Failed to decode .im4p header: %d\n", (int) ret); return false; } if (decoded.tag.length != 4 || decoded.type.length != 4) { fprintf(stderr, "Decoded .im4p header has bad tag lengths\n"); return false; } if (memcmp(decoded.tag.data, "IM4P", 4) != 0) { fprintf(stderr, "DER file schema matches but not an IM4P?\n"); return false; } uint32_t der_type = 0; ret = DERParseInteger(&decoded.type, &der_type); if (ret != DR_Success) { fprintf(stderr, "Failed to decode DER type field: %d\n", (int) ret); return false; } if (der_type != type) { fprintf(stderr, "DER type 0x%08x mismatches expected 0x%08x\n", der_type, type); return false; } // Find the payload. void *payload_addr = decoded.data.data; size_t payload_size = decoded.data.length; uint8_t *buf_end = (uint8_t *) image_buf.buf() + image_buf.size(); uint8_t *data_end = (uint8_t *) payload_addr + payload_size; if (data_end > buf_end) { fprintf(stderr, "DER data is truncated\n"); return false; } // Move the data down to the base of the buffer. memmove(image_buf.buf(), payload_addr, payload_size); image_buf.crop(payload_size); image_buf.swap(this); return true; } #endif // BOOTX2BIN_WITH_IMAGE4 bool Buffer::loadFromImg3(const char *file, uint32_t type) { // Load a payload of expected 'type' from 'file', which is in img3 // format. Returns a Buffer containing the payload. Buffer image_buf; if (!image_buf.loadFromFile(file)) { fprintf(stderr, "Couldn't load file \"%s\"\n", file); return false; } // Make a handle for the buffer. Image3ObjectHandle handle; if (image3InstantiateFromBuffer(&handle, image_buf.buf(), image_buf.size(), false /* copy */)) { fprintf(stderr, "Image3 instantiation failed\n"); return false; } // Find the payload. void *payload_addr = NULL; size_t payload_size = 0; if (image3GetTagStruct(handle, kImage3TagTypeData, &payload_addr, &payload_size, 0)) { fprintf(stderr, "Couldn't find Image3 payload\n"); image3Discard(&handle); return false; } // Move the data down to the base of the buffer. memmove(image_buf.buf(), payload_addr, payload_size); image_buf.crop(payload_size); image_buf.swap(this); image3Discard(&handle); return true; } bool Buffer::loadFromAuto(const char *file, uint32_t type) { // Try raw - in any case we can check the type from there. if (!loadFromFile(file)) { fprintf(stderr, "Couldn't load file \"%s\"\n", file); return false; } if (memcmp(buf(), "3gmI", 4)) { #if BOOTX2BIN_WITH_IMAGE4 // Try laoding as .im4p - suppress failure message as this is just a test. if (loadFromIm4p(file, type, true)) { return true; } #endif fprintf(stderr, "Treating as raw file: %s\n", file); return true; } else { fprintf(stderr, "Treating as img3 file: %s\n", file); return loadFromImg3(file, type); } } // Externals used by Image3.c extern "C" int image3AESDecryptUsingLocalKey(void *buffer, size_t length) { fprintf(stderr, "Can't personalize\n"); return -1; } extern "C" void image3SHA1Generate(void *dataBuffer, size_t dataSize, void *hashBuffer) { sha1_calculate(dataBuffer, dataSize, hashBuffer); } extern "C" int image3PKIVerifyHash(void *hashBuffer, size_t hashSize, void *signedHashBuffer, size_t signedHashSize, void *certBlobBuffer, size_t certBlobSize, void **certCustomData, size_t *certCustomDataSize) { fprintf(stderr, "Can't verify hash\n"); return -1; } extern "C" int image3TicketVerifyHash(void *hashBuffer, size_t hashSize, uint32_t imageType, uint32_t expectedType) { fprintf(stderr, "Can't verify hash\n"); return -1; } extern "C" void *image3Malloc(size_t size) { return calloc(size, 1); } extern "C" void image3Free(void *ptr, size_t size __unused) { free(ptr); }