iBoot/tools/Buffer.cpp

238 lines
6.2 KiB
C++
Raw Permalink Normal View History

2023-07-08 13:03:17 -07:00
/*
* 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 <stdio.h>
#include <string.h>
#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 <libDER/asn1Types.h>
# include <libDER/DER_Decode.h>
# include <Img4Decode.h>
#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);
}