+//
+// 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);
+}
+
+