+
+ if (flag_h) {
+ _assert(signature != NULL);
+
+ auto algorithms(GetAlgorithms());
+
+ uint32_t data = mach_header.Swap(signature->dataoff);
+
+ uint8_t *top = reinterpret_cast<uint8_t *>(mach_header.GetBase());
+ uint8_t *blob = top + data;
+ struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
+
+ struct Candidate {
+ CodeDirectory *directory_;
+ size_t size_;
+ Algorithm &algorithm_;
+ std::string hash_;
+ };
+
+ std::map<uint8_t, Candidate> candidates;
+
+ for (size_t index(0); index != Swap(super->count); ++index) {
+ auto type(Swap(super->index[index].type));
+ if ((type == CSSLOT_CODEDIRECTORY || type >= CSSLOT_ALTERNATE) && type != CSSLOT_SIGNATURESLOT) {
+ uint32_t begin = Swap(super->index[index].offset);
+ uint32_t end = index + 1 == Swap(super->count) ? Swap(super->blob.length) : Swap(super->index[index + 1].offset);
+ struct CodeDirectory *directory = reinterpret_cast<struct CodeDirectory *>(blob + begin + sizeof(Blob));
+ auto type(directory->hashType);
+ _assert(type > 0 && type <= algorithms.size());
+ auto &algorithm(*algorithms[type - 1]);
+ uint8_t hash[algorithm.size_];
+ algorithm(hash, blob + begin, end - begin);
+ candidates.insert({type, {directory, end - begin, algorithm, Hex(hash, 20)}});
+ }
+ }
+
+ _assert(!candidates.empty());
+ auto best(candidates.end());
+ --best;
+
+ const auto directory(best->second.directory_);
+ const auto flags(Swap(directory->flags));
+
+ std::string names;
+ if (flags & kSecCodeSignatureHost)
+ names += ",host";
+ if (flags & kSecCodeSignatureAdhoc)
+ names += ",adhoc";
+ if (flags & kSecCodeSignatureForceHard)
+ names += ",hard";
+ if (flags & kSecCodeSignatureForceKill)
+ names += ",kill";
+ if (flags & kSecCodeSignatureForceExpiration)
+ names += ",expires";
+ if (flags & kSecCodeSignatureRestrict)
+ names += ",restrict";
+ if (flags & kSecCodeSignatureEnforcement)
+ names += ",enforcement";
+ if (flags & kSecCodeSignatureLibraryValidation)
+ names += ",library-validation";
+ if (flags & kSecCodeSignatureRuntime)
+ names += ",runtime";
+
+ printf("CodeDirectory v=%x size=%zd flags=0x%x(%s) hashes=%d+%d location=embedded\n",
+ Swap(directory->version), best->second.size_, flags, names.empty() ? "none" : names.c_str() + 1, Swap(directory->nCodeSlots), Swap(directory->nSpecialSlots));
+ printf("Hash type=%s size=%d\n", best->second.algorithm_.name(), directory->hashSize);
+
+ std::string choices;
+ for (const auto &candidate : candidates) {
+ auto choice(candidate.second.algorithm_.name());
+ choices += ',';
+ choices += choice;
+ printf("CandidateCDHash %s=%s\n", choice, candidate.second.hash_.c_str());
+ }
+ printf("Hash choices=%s\n", choices.c_str() + 1);
+
+ printf("CDHash=%s\n", best->second.hash_.c_str());
+ }