#include "codedirectory.h"
#include "csutilities.h"
#include "CSCommonPriv.h"
+#include <vector>
using namespace UnixPlusPlus;
switch (slot) {
case cdRequirementsSlot:
return kSecCS_REQUIREMENTSFILE;
+ case cdAlternateCodeDirectorySlots:
+ return kSecCS_REQUIREMENTSFILE "-1";
+ case cdAlternateCodeDirectorySlots+1:
+ return kSecCS_REQUIREMENTSFILE "-2";
+ case cdAlternateCodeDirectorySlots+2:
+ return kSecCS_REQUIREMENTSFILE "-3";
+ case cdAlternateCodeDirectorySlots+3:
+ return kSecCS_REQUIREMENTSFILE "-4";
+ case cdAlternateCodeDirectorySlots+4:
+ return kSecCS_REQUIREMENTSFILE "-5";
case cdResourceDirSlot:
return kSecCS_RESOURCEDIRFILE;
case cdCodeDirectorySlot:
return kSecCS_CODEDIRECTORYFILE;
case cdSignatureSlot:
return kSecCS_SIGNATUREFILE;
- case cdApplicationSlot:
- return kSecCS_APPLICATIONFILE;
+ case cdTopDirectorySlot:
+ return kSecCS_TOPDIRECTORYFILE;
case cdEntitlementSlot:
return kSecCS_ENTITLEMENTFILE;
+ case cdRepSpecificSlot:
+ return kSecCS_REPSPECIFICFILE;
default:
return NULL;
}
case cdRequirementsSlot:
return cdComponentIsBlob; // global
case cdCodeDirectorySlot:
- return cdComponentPerArchitecture | cdComponentIsBlob;
+ case cdAlternateCodeDirectorySlots:
+ case cdAlternateCodeDirectorySlots+1:
+ case cdAlternateCodeDirectorySlots+2:
+ case cdAlternateCodeDirectorySlots+3:
+ case cdAlternateCodeDirectorySlots+4:
+ return cdComponentPerArchitecture | cdComponentIsBlob;
case cdSignatureSlot:
return cdComponentPerArchitecture; // raw
case cdEntitlementSlot:
"info",
"requirements",
"resources",
- "application",
+ "rep-specific",
"entitlement"
};
#endif //NDEBUG
if (version < earliestVersion)
MacOSError::throwMe(errSecCSSignatureUnsupported); // too old - can't support
if (version > currentVersion)
- secdebug("codedir", "%p version 0x%x newer than current 0x%x",
+ secinfo("codedir", "%p version 0x%x newer than current 0x%x",
this, uint32_t(version), currentVersion);
// now check interior offsets for validity
}
// check consistency between the page-coverage fields
+ size_t limit = signingLimit();
if (pageSize) {
- if (codeLimit == 0) // can't have paged signatures with no covered data
+ if (limit == 0) // can't have paged signatures with no covered data
MacOSError::throwMe(errSecCSSignatureFailed);
- size_t coveredPages = ((codeLimit-1) >> pageSize) + 1; // page slots required to cover codeLimit
+ size_t coveredPages = ((limit-1) >> pageSize) + 1; // page slots required to cover signingLimit
if (coveredPages != nCodeSlots)
MacOSError::throwMe(errSecCSSignatureFailed);
} else {
- if ((codeLimit > 0) != nCodeSlots) // must have one code slot, or none if no code
+ if ((limit > 0) != nCodeSlots) // must have one code slot, or none if no code
MacOSError::throwMe(errSecCSSignatureFailed);
}
}
//
bool CodeDirectory::validateSlot(const void *data, size_t length, Slot slot) const
{
- secdebug("codedir", "%p validating slot %d", this, int(slot));
+ secinfo("codedir", "%p validating slot %d", this, int(slot));
MakeHash<CodeDirectory> hasher(this);
Hashing::Byte digest[hasher->digestLength()];
generateHash(hasher, data, length, digest);
switch (hashType) {
case kSecCodeSignatureHashSHA1: return new CCHashInstance(kCCDigestSHA1);
case kSecCodeSignatureHashSHA256: return new CCHashInstance(kCCDigestSHA256);
+ case kSecCodeSignatureHashSHA384: return new CCHashInstance(kCCDigestSHA384);
case kSecCodeSignatureHashSHA256Truncated: return new CCHashInstance(kCCDigestSHA256, SHA1::digestLength);
default:
MacOSError::throwMe(errSecCSSignatureUnsupported);
}
+//
+// Determine which of a set of possible digest types should be chosen as the "best" one
+//
+static const CodeDirectory::HashAlgorithm hashPriorities[] = {
+ kSecCodeSignatureHashSHA384,
+ kSecCodeSignatureHashSHA256,
+ kSecCodeSignatureHashSHA256Truncated,
+ kSecCodeSignatureHashSHA1,
+ kSecCodeSignatureNoHash // sentinel
+};
+
+bool CodeDirectory::viableHash(HashAlgorithm type)
+{
+ for (const HashAlgorithm* tp = hashPriorities; *tp != kSecCodeSignatureNoHash; tp++)
+ if (*tp == type)
+ return true;
+ return false;
+
+}
+
+CodeDirectory::HashAlgorithm CodeDirectory::bestHashOf(const HashAlgorithms &types)
+{
+ for (const HashAlgorithm* type = hashPriorities; *type != kSecCodeSignatureNoHash; type++)
+ if (types.find(*type) != types.end())
+ return *type;
+ MacOSError::throwMe(errSecCSUnsupportedDigestAlgorithm);
+}
+
+
+//
+// Hash a file range with multiple digest algorithms and then pass the resulting
+// digests to a per-algorithm block.
+//
+void CodeDirectory::multipleHashFileData(FileDesc fd, size_t limit, CodeDirectory::HashAlgorithms types, void (^action)(HashAlgorithm type, DynamicHash* hasher))
+{
+ assert(!types.empty());
+ map<HashAlgorithm, RefPointer<DynamicHash> > hashes;
+ for (auto it = types.begin(); it != types.end(); ++it) {
+ if (CodeDirectory::viableHash(*it))
+ hashes[*it] = CodeDirectory::hashFor(*it);
+ }
+ scanFileData(fd, limit, ^(const void *buffer, size_t size) {
+ for (auto it = hashes.begin(); it != hashes.end(); ++it) {
+ it->second->update(buffer, size);
+ }
+ });
+ CFRef<CFMutableDictionaryRef> result = makeCFMutableDictionary();
+ for (auto it = hashes.begin(); it != hashes.end(); ++it) {
+ action(it->first, it->second);
+ }
+}
+
+
+ //
+ // Hash data in memory using our hashAlgorithm()
+ //
+bool CodeDirectory::verifyMemoryContent(CFDataRef data, const Byte* digest) const
+{
+ RefPointer<DynamicHash> hasher = CodeDirectory::hashFor(this->hashType);
+ hasher->update(CFDataGetBytePtr(data), CFDataGetLength(data));
+ return hasher->verify(digest);
+}
+
+
//
// Generate the canonical cdhash - the internal hash of the CodeDirectory itself.
// We currently truncate to 20 bytes because that's what the kernel can deal with.
{
if (slotIsPresent(-cdInfoSlot)) // has Info.plist
return "I" + hexHash((*this)[-cdInfoSlot]); // use Info.plist hash
+ if (slotIsPresent(-cdRepSpecificSlot)) // has Info.plist
+ return "R" + hexHash((*this)[-cdRepSpecificSlot]); // use Info.plist hash
if (pageSize == 0) // good-enough proxy for "not a Mach-O file"
return "M" + hexHash((*this)[0]); // use hash of main executable
return "N"; // no suitable screening code