--- /dev/null
+/*
+ * Copyright (c) 2000-2001,2011,2013-2014 Apple Inc. All Rights Reserved.
+ *
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please obtain
+ * a copy of the License at http://www.apple.com/publicsource and read it before
+ * using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
+ * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
+ * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
+ * specific language governing rights and limitations under the License.
+ */
+
+
+//
+// osxsigner - MacOS X's standard code signing algorithm.
+//
+#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 {
+
+
+//
+// Create a Verifier from a code object.
+//
+// This does not add any auxiliary information blobs. You can do that
+// by calling add() after construction, of course.
+//
+OSXVerifier::OSXVerifier(OSXCode *code)
+{
+ mPath = code->canonicalPath();
+ secdebug("codesign", "building verifier for %s", mPath.c_str());
+
+ // build new-style verifier
+ CFRef<SecStaticCodeRef> staticCode = code->codeRef();
+ switch (OSStatus rc = SecCodeCopyDesignatedRequirement(staticCode,
+ kSecCSDefaultFlags, &mRequirement.aref())) {
+ case errSecSuccess:
+ secdebug("codesign", " is signed; canonical requirement loaded");
+ break;
+ case errSecCSUnsigned:
+ secdebug("codesign", " is unsigned; no requirement");
+ break;
+ default:
+ MacOSError::throwMe(rc);
+ }
+
+ // build old-style verifier
+ makeLegacyHash(code, mLegacyHash);
+ secdebug("codesign", " hash generated");
+}
+
+
+//
+// Create a Verifier from hash, path, and requirement.
+// Again, this has no auxiliary data when constructed.
+//
+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);
+}
+
+
+//
+// Add an auxiliary comment blob.
+// Note that we only allow one auxiliary blob for each magic number.
+//
+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();
+ }
+}
+
+
+//
+// Find a comment blob, by magic number
+//
+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);
+}
+
+
+//
+// The AuxMap helper class provides a map-to-Blob-pointers with automatic memory management.
+//
+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
+
+} // end namespace Security