#include "codedirectory.h"
#include "csutilities.h"
#include "CSCommonPriv.h"
using namespace UnixPlusPlus;
namespace Security {
namespace CodeSigning {
CodeDirectory::SpecialSlot CodeDirectory::maxSpecialSlot() const
{
SpecialSlot slot = this->nSpecialSlots;
if (slot > cdSlotMax)
slot = cdSlotMax;
return slot;
}
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; case cdIdentificationSlot:
return cdComponentPerArchitecture; default:
return 0; }
}
#if !defined(NDEBUG)
const char * const CodeDirectory::debugSlotName[] = {
"codedirectory",
"info",
"requirements",
"resources",
"application",
"entitlement"
};
#endif //NDEBUG
void CodeDirectory::checkIntegrity() const
{
if (!this->validateBlob())
MacOSError::throwMe(errSecCSSignatureInvalid); if (version > compatibilityLimit)
MacOSError::throwMe(errSecCSSignatureUnsupported); if (version < earliestVersion)
MacOSError::throwMe(errSecCSSignatureUnsupported); if (version > currentVersion)
secdebug("codedir", "%p version 0x%x newer than current 0x%x",
this, uint32_t(version), currentVersion);
if (!stringAt(identOffset))
MacOSError::throwMe(errSecCSSignatureFailed); if (!contains(hashOffset - uint64_t(hashSize) * nSpecialSlots, hashSize * (uint64_t(nSpecialSlots) + nCodeSlots)))
MacOSError::throwMe(errSecCSSignatureFailed); if (const Scatter *scatter = this->scatterVector()) {
unsigned int pagesConsumed = 0;
while (scatter->count) {
if (!contains(scatter, sizeof(Scatter)))
MacOSError::throwMe(errSecCSSignatureFailed);
pagesConsumed += scatter->count;
scatter++;
}
if (!contains(scatter, sizeof(Scatter))) MacOSError::throwMe(errSecCSSignatureFailed);
if (!contains((*this)[pagesConsumed-1], hashSize)) MacOSError::throwMe(errSecCSSignatureFailed);
}
}
bool CodeDirectory::validateSlot(const void *data, size_t length, Slot slot) const
{
secdebug("codedir", "%p validating slot %d", this, int(slot));
MakeHash<CodeDirectory> hasher(this);
Hashing::Byte digest[hasher->digestLength()];
generateHash(hasher, data, length, digest);
return memcmp(digest, (*this)[slot], hasher->digestLength()) == 0;
}
bool CodeDirectory::validateSlot(FileDesc fd, size_t length, Slot slot) const
{
MakeHash<CodeDirectory> hasher(this);
Hashing::Byte digest[hasher->digestLength()];
generateHash(hasher, fd, digest, length);
return memcmp(digest, (*this)[slot], hasher->digestLength()) == 0;
}
bool CodeDirectory::slotIsPresent(Slot slot) const
{
if (slot >= -Slot(nSpecialSlots) && slot < Slot(nCodeSlots)) {
const Hashing::Byte *digest = (*this)[slot];
for (unsigned n = 0; n < hashSize; n++)
if (digest[n])
return true; }
return false; }
DynamicHash *CodeDirectory::hashFor(HashAlgorithm hashType)
{
CCDigestAlg alg;
switch (hashType) {
case kSecCodeSignatureHashSHA1: alg = kCCDigestSHA1; break;
case kSecCodeSignatureHashSHA256: alg = kCCDigestSHA256; break;
case kSecCodeSignatureHashPrestandardSkein160x256: alg = kCCDigestSkein160; break;
case kSecCodeSignatureHashPrestandardSkein256x512: alg = kCCDigestSkein256; break;
default:
MacOSError::throwMe(errSecCSSignatureUnsupported);
}
return new CCHashInstance(alg);
}
size_t CodeDirectory::generateHash(DynamicHash *hasher, FileDesc fd, Hashing::Byte *digest, size_t limit)
{
size_t size = hashFileData(fd, hasher, limit);
hasher->finish(digest);
return size;
}
size_t CodeDirectory::generateHash(DynamicHash *hasher, const void *data, size_t length, Hashing::Byte *digest)
{
hasher->update(data, length);
hasher->finish(digest);
return length;
}
std::string CodeDirectory::hexHash(const unsigned char *hash) const
{
size_t size = this->hashSize;
char result[2*size+1];
for (unsigned n = 0; n < size; n++)
sprintf(result+2*n, "%02.2x", hash[n]);
return result;
}
std::string CodeDirectory::screeningCode() const
{
if (slotIsPresent(-cdInfoSlot)) return "I" + hexHash((*this)[-cdInfoSlot]); if (pageSize == 0) return "M" + hexHash((*this)[0]); return "N"; }
} }
const SecCodeDirectoryFlagTable kSecCodeDirectoryFlagTable[] = {
{ "host", kSecCodeSignatureHost, true },
{ "adhoc", kSecCodeSignatureAdhoc, false },
{ "hard", kSecCodeSignatureForceHard, true },
{ "kill", kSecCodeSignatureForceKill, true },
{ "expires", kSecCodeSignatureForceExpiration, true },
{ NULL }
};