#include "codedirectory.h"
#include "CSCommon.h"
using namespace UnixPlusPlus;
namespace Security {
namespace CodeSigning {
const char *CodeDirectory::canonicalSlotName(SpecialSlot slot)
{
switch (slot) {
case cdRequirementsSlot:
return kSecCS_REQUIREMENTSFILE;
case cdResourceDirSlot:
return kSecCS_RESOURCEDIRFILE;
case cdCodeDirectorySlot:
return kSecCS_CODEDIRECTORYFILE;
case cdSignatureSlot:
return kSecCS_SIGNATUREFILE;
case cdApplicationSlot:
return kSecCS_APPLICATIONFILE;
case cdEntitlementSlot:
return kSecCS_ENTITLEMENTFILE;
default:
return NULL;
}
}
unsigned CodeDirectory::slotAttributes(SpecialSlot slot)
{
switch (slot) {
case cdRequirementsSlot:
return cdComponentIsBlob; case cdCodeDirectorySlot:
return cdComponentPerArchitecture | cdComponentIsBlob;
case cdSignatureSlot:
return cdComponentPerArchitecture; case cdEntitlementSlot:
return cdComponentIsBlob; default:
return 0; }
}
#if !defined(NDEBUG)
const char * const CodeDirectory::debugSlotName[] = {
"codedirectory",
"info",
"requirements",
"resources",
"application"
};
#endif //NDEBUG
void CodeDirectory::checkVersion() const
{
if (!this->validateBlob())
MacOSError::throwMe(errSecCSSignatureInvalid); if (version > compatibilityLimit)
MacOSError::throwMe(errSecCSSignatureUnsupported); if (version > currentVersion)
secdebug("codedir", "%p version 0x%x newer than current 0x%x",
this, uint32_t(version), currentVersion);
}
bool CodeDirectory::validateSlot(const void *data, size_t length, Slot slot) const
{
secdebug("codedir", "%p validating slot %d", this, int(slot));
Hash::Byte digest[Hash::digestLength];
hash(data, length, digest);
return memcmp(digest, (*this)[slot], Hash::digestLength) == 0;
}
bool CodeDirectory::validateSlot(FileDesc fd, size_t length, Slot slot) const
{
Hash::Digest digest;
hash(fd, digest, length);
return memcmp(digest, (*this)[slot], Hash::digestLength) == 0;
}
bool CodeDirectory::slotIsPresent(Slot slot) const
{
if (slot >= -Slot(nSpecialSlots) && slot < Slot(nCodeSlots)) {
const Hash::Byte *digest = (*this)[slot];
for (unsigned n = 0; n < Hash::digestLength; n++)
if (digest[n])
return true; }
return false; }
size_t CodeDirectory::hash(FileDesc fd, Hash::Byte *digest, size_t limit)
{
IFDEBUG(size_t hpos = fd.position());
IFDEBUG(size_t hlimit = limit);
unsigned char buffer[4096];
Hash hash;
size_t total = 0;
for (;;) {
size_t size = sizeof(buffer);
if (limit && limit < size)
size = limit;
size_t got = fd.read(buffer, size);
total += got;
if (fd.atEnd())
break;
hash(buffer, got);
if (limit && (limit -= got) == 0)
break;
}
hash.finish(digest);
secdebug("cdhash", "fd %d %zd@0x%zx => %2x.%2x.%2x...",
fd.fd(), hpos, hlimit, digest[0], digest[1], digest[2]);
return total;
}
size_t CodeDirectory::hash(const void *data, size_t length, Hash::Byte *digest)
{
Hash hash;
hash(data, length);
hash.finish(digest);
return length;
}
const CodeDirectory::FlagItem CodeDirectory::flagItems[] = {
{ "host", kSecCodeSignatureHost, true },
{ "adhoc", kSecCodeSignatureAdhoc, false },
{ "hard", kSecCodeSignatureForceHard, true },
{ "kill", kSecCodeSignatureForceKill, true },
{ "expires", kSecCodeSignatureForceExpiration, true },
{ NULL }
};
uint32_t CodeDirectory::textFlags(std::string text)
{
uint32_t flags = 0;
for (string::size_type comma = text.find(','); ; text = text.substr(comma+1), comma = text.find(',')) {
string word = (comma == string::npos) ? text : text.substr(0, comma);
const CodeDirectory::FlagItem *item;
for (item = CodeDirectory::flagItems; item->name; item++)
if (item->external && !strncmp(word.c_str(), item->name, word.size())) {
flags |= item->value;
break;
}
if (!item) MacOSError::throwMe(errSecCSInvalidFlags);
if (comma == string::npos) break;
}
return flags;
}
} }