#include <security_cdsa_utilities/osxverifier.h>
#include <security_utilities/unix++.h>
#include <security_utilities/hashing.h>
#include <security_utilities/memutils.h>
#include <security_utilities/debugging.h>
#include <security_codesigning/requirement.h>
#include <security_codesigning/reqdumper.h> // debug only
using namespace CodeSigning;
namespace Security {
OSXVerifier::OSXVerifier(OSXCode *code)
{
mPath = code->canonicalPath();
secdebug("codesign", "building verifier for %s", mPath.c_str());
CFRef<SecStaticCodeRef> staticCode = code->codeRef();
switch (OSStatus rc = SecCodeCopyDesignatedRequirement(staticCode,
kSecCSDefaultFlags, &mRequirement.aref())) {
case noErr:
secdebug("codesign", " is signed; canonical requirement loaded");
break;
case errSecCSUnsigned:
secdebug("codesign", " is unsigned; no requirement");
break;
default:
MacOSError::throwMe(rc);
}
makeLegacyHash(code, mLegacyHash);
secdebug("codesign", " hash generated");
}
OSXVerifier::OSXVerifier(const SHA1::Byte *hash, const std::string &path)
: mPath(path)
{
secdebug("codesign", "building verifier from hash %p and path=%s", hash, path.c_str());
if (hash)
memcpy(mLegacyHash, hash, sizeof(mLegacyHash));
else
memset(mLegacyHash, 0, sizeof(mLegacyHash));
}
OSXVerifier::~OSXVerifier()
{
secdebug("codesign", "%p verifier destroyed", this);
}
void OSXVerifier::add(const BlobCore *blob)
{
if (blob->is<Requirement>()) {
#if defined(NDEBUG)
secdebug("codesign", "%p verifier adds requirement", this);
#else
secdebug("codesign", "%p verifier adds requirement %s", this,
Dumper::dump(Requirement::specific(blob), true).c_str());
#endif //NDEBUG
MacOSError::check(SecRequirementCreateWithData(CFTempData(*blob),
kSecCSDefaultFlags, &mRequirement.aref()));
} else {
secdebug("codesign", "%p verifier adds blob (0x%x,%zd)",
this, blob->magic(), blob->length());
BlobCore * &slot = mAuxiliary[blob->magic()];
if (slot)
::free(slot);
slot = blob->clone();
}
}
const BlobCore *OSXVerifier::find(BlobCore::Magic magic)
{
AuxMap::const_iterator it = mAuxiliary.find(magic);
return (it == mAuxiliary.end()) ? NULL : it->second;
}
void OSXVerifier::makeLegacyHash(OSXCode *code, SHA1::Digest digest)
{
secdebug("codesign", "calculating legacy hash for %s", code->canonicalPath().c_str());
UnixPlusPlus::AutoFileDesc fd(code->executablePath(), O_RDONLY);
char buffer[legacyHashLimit];
size_t size = fd.read(buffer, legacyHashLimit);
SHA1 hash;
hash(buffer, size);
hash.finish(digest);
}
OSXVerifier::AuxMap::AuxMap(const OSXVerifier::AuxMap &src)
{
for (const_iterator it = src.begin(); it != src.end(); it++)
this->insert(*it);
}
OSXVerifier::AuxMap::~AuxMap()
{
for (const_iterator it = this->begin(); it != this->end(); ++it)
::free(it->second);
}
#if DEBUGDUMP
void OSXVerifier::dump() const
{
static const SHA1::Digest nullDigest = { 0 };
if (!memcmp(mLegacyHash, nullDigest, sizeof(mLegacyHash))) {
Debug::dump("(no hash)");
} else {
Debug::dump("oldHash=");
Debug::dumpData(mLegacyHash, sizeof(mLegacyHash));
}
if (mRequirement) {
CFRef<CFDataRef> reqData;
if (!SecRequirementCopyData(mRequirement, 0, &reqData.aref())) {
Debug::dump(" Requirement =>");
((const Requirement *)CFDataGetBytePtr(reqData))->dump();
}
} else {
Debug::dump(" NO REQ");
}
}
#endif //DEBUGDUMP
}