X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/fa7225c82381bac4432a6edf16f53b5370238d85..7e6b461318c8a779d91381531435a68ee4e8b6ed:/OSX/libsecurity_codesigning/lib/codedirectory.cpp?ds=sidebyside diff --git a/OSX/libsecurity_codesigning/lib/codedirectory.cpp b/OSX/libsecurity_codesigning/lib/codedirectory.cpp index b14b58ec..4d3c1c80 100644 --- a/OSX/libsecurity_codesigning/lib/codedirectory.cpp +++ b/OSX/libsecurity_codesigning/lib/codedirectory.cpp @@ -79,6 +79,8 @@ const char *CodeDirectory::canonicalSlotName(SpecialSlot slot) return kSecCS_TOPDIRECTORYFILE; case cdEntitlementSlot: return kSecCS_ENTITLEMENTFILE; + case cdEntitlementDERSlot: + return kSecCS_ENTITLEMENTDERFILE; case cdRepSpecificSlot: return kSecCS_REPSPECIFICFILE; default: @@ -105,9 +107,12 @@ unsigned CodeDirectory::slotAttributes(SpecialSlot slot) case cdSignatureSlot: return cdComponentPerArchitecture; // raw case cdEntitlementSlot: + case cdEntitlementDERSlot: return cdComponentIsBlob; // global case cdIdentificationSlot: return cdComponentPerArchitecture; // raw + case cdTicketSlot: + return 0; // global, raw default: return 0; // global, raw } @@ -157,7 +162,9 @@ void CodeDirectory::checkIntegrity() const if (version > currentVersion) secinfo("codedir", "%p version 0x%x newer than current 0x%x", this, uint32_t(version), currentVersion); - + + bool hasPreEncryptHashes = version >= supportsPreEncrypt && preEncryptOffset != 0; + // now check interior offsets for validity if (!stringAt(identOffset)) MacOSError::throwMe(errSecCSSignatureFailed); // identifier out of blob range @@ -165,6 +172,8 @@ void CodeDirectory::checkIntegrity() const MacOSError::throwMe(errSecCSSignatureFailed); // identifier out of blob range if (!contains(hashOffset - int64_t(hashSize) * nSpecialSlots, hashSize * (int64_t(nSpecialSlots) + nCodeSlots))) MacOSError::throwMe(errSecCSSignatureFailed); // hash array out of blob range + if (hasPreEncryptHashes && !contains(preEncryptOffset, hashSize * (int64_t(nCodeSlots)))) + MacOSError::throwMe(errSecCSSignatureFailed); // pre-encrypt array out of blob range if (const Scatter *scatter = this->scatterVector()) { // the optional scatter vector is terminated with an element having (count == 0) unsigned int pagesConsumed = 0; @@ -175,7 +184,8 @@ void CodeDirectory::checkIntegrity() const break; pagesConsumed += scatter->count; } - if (!contains((*this)[pagesConsumed-1], hashSize)) // referenced too many main hash slots + if (!contains(getSlot(pagesConsumed-1, false), hashSize) || + (hasPreEncryptHashes && !contains(getSlot(pagesConsumed-1, true), hashSize))) // referenced too many main hash slots MacOSError::throwMe(errSecCSSignatureFailed); } @@ -197,13 +207,13 @@ void CodeDirectory::checkIntegrity() const // // Validate a slot against data in memory. // -bool CodeDirectory::validateSlot(const void *data, size_t length, Slot slot) const +bool CodeDirectory::validateSlot(const void *data, size_t length, Slot slot, bool preEncrypt) const { secinfo("codedir", "%p validating slot %d", this, int(slot)); MakeHash hasher(this); - Hashing::Byte digest[hasher->digestLength()]; - generateHash(hasher, data, length, digest); - return memcmp(digest, (*this)[slot], hasher->digestLength()) == 0; + vector digest_vector(hasher->digestLength()); + generateHash(hasher, data, length, digest_vector.data()); + return memcmp(digest_vector.data(), getSlot(slot, preEncrypt), hasher->digestLength()) == 0; } @@ -211,12 +221,12 @@ bool CodeDirectory::validateSlot(const void *data, size_t length, Slot slot) con // Validate a slot against the contents of an open file. At most 'length' bytes // will be read from the file. // -bool CodeDirectory::validateSlot(FileDesc fd, size_t length, Slot slot) const +bool CodeDirectory::validateSlot(FileDesc fd, size_t length, Slot slot, bool preEncrypt) const { MakeHash hasher(this); - Hashing::Byte digest[hasher->digestLength()]; - generateHash(hasher, fd, digest, length); - return memcmp(digest, (*this)[slot], hasher->digestLength()) == 0; + vector digest_vector(hasher->digestLength()); + generateHash(hasher, fd, digest_vector.data(), length); + return memcmp(digest_vector.data(), getSlot(slot, preEncrypt), hasher->digestLength()) == 0; } @@ -228,7 +238,7 @@ bool CodeDirectory::validateSlot(FileDesc fd, size_t length, Slot slot) const bool CodeDirectory::slotIsPresent(Slot slot) const { if (slot >= -Slot(nSpecialSlots) && slot < Slot(nCodeSlots)) { - const Hashing::Byte *digest = (*this)[slot]; + const Hashing::Byte *digest = getSlot(slot, false); for (unsigned n = 0; n < hashSize; n++) if (digest[n]) return true; // non-zero digest => present @@ -292,21 +302,19 @@ CodeDirectory::HashAlgorithm CodeDirectory::bestHashOf(const HashAlgorithms &typ void CodeDirectory::multipleHashFileData(FileDesc fd, size_t limit, CodeDirectory::HashAlgorithms types, void (^action)(HashAlgorithm type, DynamicHash* hasher)) { assert(!types.empty()); - vector > hashers; + map > hashes; for (auto it = types.begin(); it != types.end(); ++it) { if (CodeDirectory::viableHash(*it)) - hashers.push_back(CodeDirectory::hashFor(*it)); + hashes[*it] = CodeDirectory::hashFor(*it); } scanFileData(fd, limit, ^(const void *buffer, size_t size) { - unsigned n = 0; - for (auto it = types.begin(); it != types.end(); ++it, ++n) { - hashers[n]->update(buffer, size); + for (auto it = hashes.begin(); it != hashes.end(); ++it) { + it->second->update(buffer, size); } }); CFRef result = makeCFMutableDictionary(); - unsigned n = 0; - for (auto it = types.begin(); it != types.end(); ++it, ++n) { - action(*it, hashers[n]); + for (auto it = hashes.begin(); it != hashes.end(); ++it) { + action(it->first, it->second); } } @@ -324,15 +332,17 @@ bool CodeDirectory::verifyMemoryContent(CFDataRef data, const Byte* digest) cons // // 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. +// With 'truncate' truncates to 20 bytes, because that's what's commonly used. // -CFDataRef CodeDirectory::cdhash() const +CFDataRef CodeDirectory::cdhash(bool truncate) const { MakeHash hash(this); - Hashing::Byte digest[hash->digestLength()]; + vector digest_vector(hash->digestLength()); hash->update(this, this->length()); - hash->finish(digest); - return makeCFData(digest, min(hash->digestLength(), size_t(kSecCodeCDHashLength))); + hash->finish(digest_vector.data()); + return makeCFData(digest_vector.data(), + truncate ? min(hash->digestLength(), size_t(kSecCodeCDHashLength)) : + hash->digestLength()); } @@ -382,11 +392,11 @@ std::string CodeDirectory::hexHash(const unsigned char *hash) const std::string CodeDirectory::screeningCode() const { if (slotIsPresent(-cdInfoSlot)) // has Info.plist - return "I" + hexHash((*this)[-cdInfoSlot]); // use Info.plist hash + return "I" + hexHash(getSlot(-cdInfoSlot, false)); // use Info.plist hash if (slotIsPresent(-cdRepSpecificSlot)) // has Info.plist - return "R" + hexHash((*this)[-cdRepSpecificSlot]); // use Info.plist hash + return "R" + hexHash(getSlot(-cdRepSpecificSlot, false)); // 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 "M" + hexHash(getSlot(0, false)); // use hash of main executable return "N"; // no suitable screening code } @@ -408,5 +418,6 @@ const SecCodeDirectoryFlagTable kSecCodeDirectoryFlagTable[] = { { "restrict", kSecCodeSignatureRestrict, true }, { "enforcement", kSecCodeSignatureEnforcement, true }, { "library-validation", kSecCodeSignatureLibraryValidation, true }, + { "runtime", kSecCodeSignatureRuntime, true }, { NULL } };