X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/866f8763175ff60e4fa455b92b5eb660a12fe6c7..refs/heads/master:/OSX/libsecurity_codesigning/lib/machorep.cpp diff --git a/OSX/libsecurity_codesigning/lib/machorep.cpp b/OSX/libsecurity_codesigning/lib/machorep.cpp index 0959b559..157e6e7a 100644 --- a/OSX/libsecurity_codesigning/lib/machorep.cpp +++ b/OSX/libsecurity_codesigning/lib/machorep.cpp @@ -25,6 +25,7 @@ // machorep - DiskRep mix-in for handling Mach-O main executables // #include "machorep.h" +#include "notarization.h" #include "StaticCode.h" #include "reqmaker.h" #include @@ -53,7 +54,7 @@ MachORep::MachORep(const char *path, const Context *ctx) if (ctx->offset) mExecutable = new Universal(fd(), (size_t)ctx->offset, ctx->size); else if (ctx->arch) { - auto_ptr full(new Universal(fd())); + unique_ptr full(new Universal(fd())); mExecutable = new Universal(fd(), full->archOffset(ctx->arch), full->archLength(ctx->arch)); } else mExecutable = new Universal(fd()); @@ -109,39 +110,32 @@ Universal *MachORep::mainExecutableImage() void MachORep::prepareForSigning(SigningContext &context) { if (context.digestAlgorithms().empty()) { - auto_ptr macho(mainExecutableImage()->architecture()); - - if (const version_min_command *version = macho->findMinVersion()) { - uint32_t limit = 0; - switch (macho->flip(version->cmd)) { - case LC_VERSION_MIN_MACOSX: + unique_ptr macho(mainExecutableImage()->architecture()); + + uint32_t limit = 0; + switch (macho->platform()) { + case 0: + // If we don't know the platform, we stay agile. + return; + case PLATFORM_MACOS: + // 10.11.4 had first proper sha256 support. limit = (10 << 16 | 11 << 8 | 4 << 0); break; -#if 0 /* need updated libMIS before we can do this switch */ - case LC_VERSION_MIN_IPHONEOS: - limit = (9 << 16 | 3 << 8); - break; - case LC_VERSION_MIN_WATCHOS: - limit = (2 << 16 | 2 << 8); - break; - case LC_VERSION_MIN_TVOS: - limit = (9 << 16 | 2 << 8); + case PLATFORM_TVOS: + case PLATFORM_IOS: + // iOS 11 and tvOS 11 had first proper sha256 support. + limit = (11 << 16 | 0 << 8 | 0 << 0); break; + case PLATFORM_WATCHOS: + // We stay agile on the watch right now. + return; default: + // All other platforms are assumed to be new and support SHA256. break; -#else - case LC_VERSION_MIN_IPHONEOS: - case LC_VERSION_MIN_WATCHOS: - case LC_VERSION_MIN_TVOS: - return; - default: - break; -#endif - } - if (macho->flip(version->version) >= limit) { - // young enough not to need SHA-1 legacy support - context.setDigestAlgorithm(kSecCodeSignatureHashSHA256); - } + } + if (macho->minVersion() >= limit) { + // young enough not to need SHA-1 legacy support + context.setDigestAlgorithm(kSecCodeSignatureHashSHA256); } } } @@ -157,39 +151,22 @@ size_t MachORep::signingBase() size_t MachORep::signingLimit() { - auto_ptr macho(mExecutable->architecture()); + unique_ptr macho(mExecutable->architecture()); return macho->signingExtent(); } bool MachORep::needsExecSeg(const MachO& macho) { - if (const version_min_command *version = macho.findMinVersion()) { - uint32_t min = UINT32_MAX; - - switch (macho.flip(version->cmd)) { - case LC_VERSION_MIN_IPHONEOS: - case LC_VERSION_MIN_TVOS: - min = (11 << 16 | 0 << 8); - break; - case LC_VERSION_MIN_WATCHOS: - min = (4 << 16 | 0 << 8); - break; - - default: - /* macOS currently does not get this. */ - return false; - } - - if (macho.flip(version->version) >= min) { - return true; - } - } - - return false; + uint32_t platform = macho.platform(); + + // Everything gets an exec segment. This is ignored + // on non-PPL devices, and explicitly wastes some + // space on those devices, but is simpler logic. + return platform != 0; } size_t MachORep::execSegBase(const Architecture *arch) { - auto_ptr macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture()); + unique_ptr macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture()); if (!needsExecSeg(*macho)) { return 0; @@ -214,7 +191,7 @@ size_t MachORep::execSegBase(const Architecture *arch) size_t MachORep::execSegLimit(const Architecture *arch) { - auto_ptr macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture()); + unique_ptr macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture()); if (!needsExecSeg(*macho)) { return 0; @@ -245,7 +222,7 @@ size_t MachORep::execSegLimit(const Architecture *arch) // CFDataRef MachORep::identification() { - std::auto_ptr macho(mainExecutableImage()->architecture()); + std::unique_ptr macho(mainExecutableImage()->architecture()); return identificationFor(macho.get()); } @@ -292,6 +269,27 @@ CFDataRef MachORep::component(CodeDirectory::SpecialSlot slot) } } +// +// Retrieve all components, used for signature editing. +// +EditableDiskRep::RawComponentMap MachORep::createRawComponents() +{ + EditableDiskRep::RawComponentMap blobMap; + + // First call to signingData() caches the result, so this + // _should_ not cause performance issues. + if (NULL == signingData()) { + MacOSError::throwMe(errSecCSUnsigned); + } + const EmbeddedSignatureBlob &blobs = *signingData(); + + for (unsigned int i = 0; i < blobs.count(); ++i) { + CodeDirectory::Slot slot = blobs.type(i); + const BlobCore *blob = blobs.blob(i); + blobMap[slot] = blobs.blobData(slot, blob); + } + return blobMap; +} // Retrieve a component from the embedded signature SuperBlob (if present). // This reads the entire signing SuperBlob when first called for an executable, @@ -302,29 +300,37 @@ CFDataRef MachORep::component(CodeDirectory::SpecialSlot slot) // calls wouldn't be slower in the end. // CFDataRef MachORep::embeddedComponent(CodeDirectory::SpecialSlot slot) +{ + if (signingData()) { + return signingData()->component(slot); + } + + // not found + return NULL; +} + + + +EmbeddedSignatureBlob *MachORep::signingData() { if (!mSigningData) { // fetch and cache - auto_ptr macho(mainExecutableImage()->architecture()); + unique_ptr macho(mainExecutableImage()->architecture()); if (macho.get()) if (const linkedit_data_command *cs = macho->findCodeSignature()) { size_t offset = macho->flip(cs->dataoff); size_t length = macho->flip(cs->datasize); if ((mSigningData = EmbeddedSignatureBlob::readBlob(macho->fd(), macho->offset() + offset, length))) { secinfo("machorep", "%zd signing bytes in %d blob(s) from %s(%s)", - mSigningData->length(), mSigningData->count(), - mainExecutablePath().c_str(), macho->architecture().name()); + mSigningData->length(), mSigningData->count(), + mainExecutablePath().c_str(), macho->architecture().name()); } else { secinfo("machorep", "failed to read signing bytes from %s(%s)", - mainExecutablePath().c_str(), macho->architecture().name()); + mainExecutablePath().c_str(), macho->architecture().name()); MacOSError::throwMe(errSecCSSignatureInvalid); } } } - if (mSigningData) - return mSigningData->component(slot); - - // not found - return NULL; + return mSigningData; } @@ -336,7 +342,7 @@ CFDataRef MachORep::infoPlist() { CFRef info; try { - auto_ptr macho(mainExecutableImage()->architecture()); + unique_ptr macho(mainExecutableImage()->architecture()); if (const section *sect = macho->findSection("__TEXT", "__info_plist")) { if (macho->is64()) { const section_64 *sect64 = reinterpret_cast(sect); @@ -395,18 +401,31 @@ void MachORep::flush() CFDictionaryRef MachORep::diskRepInformation() { - auto_ptr macho (mainExecutableImage()->architecture()); + unique_ptr macho (mainExecutableImage()->architecture()); CFRef info; - if (const version_min_command *version = macho->findMinVersion()) { - + uint32_t platform = 0; + uint32_t minVersion = 0; + uint32_t sdkVersion = 0; + + if (macho->version(&platform, &minVersion, &sdkVersion)) { + + /* These keys replace the old kSecCodeInfoDiskRepOSPlatform, kSecCodeInfoDiskRepOSVersionMin + * and kSecCodeInfoDiskRepOSSDKVersion. The keys were renamed because we changed what value + * "platform" represents: For the old key, the actual load command (e.g. LC_VERSION_MIN_MACOSX) + * was returned; for the new key, we return one of the PLATFORM_* values used by LC_BUILD_VERSION. + * + * The keys are private and undocumented, and maintaining a translation table between the old and + * new domain would provide little value at high cost, but we do remove the old keys to make + * the change obvious. + */ + info.take(cfmake("{%O = %d,%O = %d,%O = %d}", - kSecCodeInfoDiskRepOSPlatform, macho->flip(version->cmd), - kSecCodeInfoDiskRepOSVersionMin, macho->flip(version->version), - kSecCodeInfoDiskRepOSSDKVersion, macho->flip(version->sdk))); + kSecCodeInfoDiskRepVersionPlatform, platform, + kSecCodeInfoDiskRepVersionMin, minVersion, + kSecCodeInfoDiskRepVersionSDK, sdkVersion)); - if (macho->flip(version->cmd) == LC_VERSION_MIN_MACOSX && - macho->flip(version->sdk) < (10 << 16 | 9 << 8)) + if (platform == PLATFORM_MACOS && sdkVersion < (10 << 16 | 9 << 8)) { info.take(cfmake("{+%O, %O = 'OS X SDK version before 10.9 does not support Library Validation'}", info.get(), @@ -460,7 +479,7 @@ const Requirements *MachORep::defaultRequirements(const Architecture *arch, cons Requirement *MachORep::libraryRequirements(const Architecture *arch, const SigningContext &ctx) { - auto_ptr macho(mainExecutableImage()->architecture(*arch)); + unique_ptr macho(mainExecutableImage()->architecture(*arch)); Requirement::Maker maker; Requirement::Maker::Chain chain(maker, opOr); @@ -555,6 +574,14 @@ void MachORep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data MacOSError::throwMe(errSecCSInternalError); } +void MachORep::registerStapledTicket() +{ + CFRef data = NULL; + if (mSigningData) { + data.take(mSigningData->component(cdTicketSlot)); + registerStapledTicketInMachO(data); + } +} } // end namespace CodeSigning } // end namespace Security