#include "cfmdiskrep.h"
#include <cstring>
namespace Security {
namespace CodeSigning {
using namespace UnixPlusPlus;
CFMDiskRep::CFMDiskRep(const char *path)
: SingleDiskRep(path), mTriedRead(false)
{
CODESIGN_DISKREP_CREATE_CFM(this, (char*)path);
}
CFMDiskRep::~CFMDiskRep()
{
if (mTriedRead)
delete mSigningData;
}
bool CFMDiskRep::candidate(FileDesc &fd)
{
static const char magicMarker[] = "Joy!peffpwpc";
static const size_t magicLength = 12;
static const size_t scanLength = 128;
static const size_t scanAlignment = 4;
char marker[scanLength];
if (fd.read(marker, scanLength, 0) == scanLength)
for (size_t p = 0; p <= scanLength - magicLength; p += scanAlignment)
if (!memcmp(marker+p, magicMarker, magicLength))
return true;
return false;
}
CFDataRef CFMDiskRep::component(CodeDirectory::SpecialSlot slot)
{
if (!mTriedRead)
readSigningData();
if (mSigningData)
return mSigningData->component(slot);
else
return NULL;
}
size_t CFMDiskRep::signingLimit()
{
readSigningData();
if (mSigningData)
return mSigningOffset;
else
return fd().fileSize();
}
string CFMDiskRep::format()
{
return "CFM/PEF binary";
}
void CFMDiskRep::flush()
{
mTriedRead = false;
::free(mSigningData);
}
static const uint8_t cfm_ireqs[] = { 0xfa, 0xde, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x14, 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16,
0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68,
0x43, 0x46, 0x4d, 0x41, 0x70, 0x70, 0x00, 0x00,
};
const Requirements *CFMDiskRep::defaultRequirements(const Architecture *, const SigningContext &)
{
return ((const Requirements *)cfm_ireqs)->clone(); }
size_t CFMDiskRep::pageSize(const SigningContext &)
{
return segmentedPageSize;
}
void CFMDiskRep::readSigningData()
{
if (!mTriedRead) { mSigningData = NULL; mTriedRead = true;
FileDesc &fd = this->fd();
fd.seek(fd.fileSize() - sizeof(Sentinel));
Sentinel sentinel;
if (fd.read(&sentinel, sizeof(sentinel), fd.fileSize() - sizeof(Sentinel)) == sizeof(Sentinel))
if (sentinel.magic == EmbeddedSignatureBlob::typeMagic) {
mSigningOffset = sentinel.offset;
if ((mSigningData = EmbeddedSignatureBlob::readBlob(fd, mSigningOffset)))
secdebug("cfmrep", "%zd signing bytes in %d blob(s) from %s(CFM)",
mSigningData->length(), mSigningData->count(),
mainExecutablePath().c_str());
else
secdebug("cfmrep", "failed to read signing bytes from %s(CFM)",
mainExecutablePath().c_str());
}
}
}
DiskRep::Writer *CFMDiskRep::writer()
{
return new Writer(this);
}
CFMDiskRep::Writer::~Writer()
{
delete mSigningData;
}
void CFMDiskRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
{
EmbeddedSignatureBlob::Maker::component(slot, data);
}
void CFMDiskRep::Writer::flush()
{
delete mSigningData; mSigningData = Maker::make(); size_t start = LowLevelMemoryUtilities::alignUp(rep->signingLimit(), 16);
Sentinel sentinel;
sentinel.magic = EmbeddedSignatureBlob::typeMagic;
sentinel.offset = start;
AutoFileDesc fd(rep->path(), O_RDWR);
fd.seek(start);
fd.writeAll(mSigningData, mSigningData->length());
fd.writeAll(&sentinel, sizeof(sentinel));
}
} }