+
+
+//
+// A collector of CodeDirectories for hash-agile construction of signatures.
+//
+CodeDirectorySet::~CodeDirectorySet()
+{
+ for (auto it = begin(); it != end(); ++it)
+ ::free(const_cast<CodeDirectory*>(it->second));
+}
+
+
+void CodeDirectorySet::add(const Security::CodeSigning::CodeDirectory *cd)
+{
+ insert(make_pair(cd->hashType, cd));
+ if (cd->hashType == kSecCodeSignatureHashSHA1)
+ mPrimary = cd;
+}
+
+
+void CodeDirectorySet::populate(DiskRep::Writer *writer) const
+{
+ assert(!empty());
+
+ if (mPrimary == NULL) // didn't add SHA-1; pick another occupant for this slot
+ mPrimary = begin()->second;
+
+ // reserve slot zero for a SHA-1 digest if present; else pick something else
+ CodeDirectory::SpecialSlot nextAlternate = cdAlternateCodeDirectorySlots;
+ for (auto it = begin(); it != end(); ++it) {
+ if (it->second == mPrimary) {
+ writer->codeDirectory(it->second, cdCodeDirectorySlot);
+ } else {
+ writer->codeDirectory(it->second, nextAlternate++);
+ }
+ }
+}
+
+
+const CodeDirectory* CodeDirectorySet::primary() const
+{
+ if (mPrimary == NULL)
+ mPrimary = begin()->second;
+ return mPrimary;
+}
+
+CFArrayRef CodeDirectorySet::hashList() const
+{
+ CFRef<CFMutableArrayRef> hashList = makeCFMutableArray(0);
+ for (auto it = begin(); it != end(); ++it) {
+ CFRef<CFDataRef> cdhash = it->second->cdhash(true);
+ CFArrayAppendValue(hashList, cdhash);
+ }
+ return hashList.yield();
+}
+
+CFDictionaryRef CodeDirectorySet::hashDict() const
+{
+ CFRef<CFMutableDictionaryRef> hashDict = makeCFMutableDictionary();
+
+ for (auto it = begin(); it != end(); ++it) {
+ SECOidTag tag = CodeDirectorySet::SECOidTagForAlgorithm(it->first);
+
+ if (tag == SEC_OID_UNKNOWN) {
+ MacOSError::throwMe(errSecCSUnsupportedDigestAlgorithm);
+ }
+
+ CFRef<CFNumberRef> hashType = makeCFNumber(int(tag));
+ CFRef<CFDataRef> fullCdhash = it->second->cdhash(false); // Full-length cdhash!
+ CFDictionarySetValue(hashDict, hashType, fullCdhash);
+ }
+
+ return hashDict.yield();
+}
+
+SECOidTag CodeDirectorySet::SECOidTagForAlgorithm(CodeDirectory::HashAlgorithm algorithm) {
+ SECOidTag tag;
+
+ switch (algorithm) {
+ case kSecCodeSignatureHashSHA1:
+ tag = SEC_OID_SHA1;
+ break;
+ case kSecCodeSignatureHashSHA256:
+ case kSecCodeSignatureHashSHA256Truncated: // truncated *page* hashes, not cdhash
+ tag = SEC_OID_SHA256;
+ break;
+ case kSecCodeSignatureHashSHA384:
+ tag = SEC_OID_SHA384;
+ break;
+ default:
+ tag = SEC_OID_UNKNOWN;
+ }
+
+ return tag;
+}
+