]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_codesigning/lib/machorep.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / machorep.cpp
index 0959b5595040c50434ef6881ede05a869b312bcc..157e6e7aabe08bab7660acb00a46fbf032e014f6 100644 (file)
@@ -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 <security_utilities/logging.h>
@@ -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<Universal> full(new Universal(fd()));
+                       unique_ptr<Universal> 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> 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> 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> macho(mExecutable->architecture());
+       unique_ptr<MachO> 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> macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture());
+       unique_ptr<MachO> 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> macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture());
+       unique_ptr<MachO> 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> macho(mainExecutableImage()->architecture());
+       std::unique_ptr<MachO> 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> macho(mainExecutableImage()->architecture());
+               unique_ptr<MachO> 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<CFDataRef> info;
        try {
-               auto_ptr<MachO> macho(mainExecutableImage()->architecture());
+               unique_ptr<MachO> macho(mainExecutableImage()->architecture());
                if (const section *sect = macho->findSection("__TEXT", "__info_plist")) {
                        if (macho->is64()) {
                                const section_64 *sect64 = reinterpret_cast<const section_64 *>(sect);
@@ -395,18 +401,31 @@ void MachORep::flush()
 
 CFDictionaryRef MachORep::diskRepInformation()
 {
-    auto_ptr<MachO> macho (mainExecutableImage()->architecture());
+    unique_ptr<MachO> macho (mainExecutableImage()->architecture());
     CFRef<CFDictionaryRef> 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<CFMutableDictionaryRef>("{%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<CFMutableDictionaryRef>("{+%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> macho(mainExecutableImage()->architecture(*arch));
+       unique_ptr<MachO> 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<CFDataRef> data = NULL;
+       if (mSigningData) {
+               data.take(mSigningData->component(cdTicketSlot));
+               registerStapledTicketInMachO(data);
+       }
+}
 
 } // end namespace CodeSigning
 } // end namespace Security