X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_manifest/lib/AppleManifest.cpp diff --git a/Security/libsecurity_manifest/lib/AppleManifest.cpp b/Security/libsecurity_manifest/lib/AppleManifest.cpp deleted file mode 100644 index 31db9426..00000000 --- a/Security/libsecurity_manifest/lib/AppleManifest.cpp +++ /dev/null @@ -1,858 +0,0 @@ -#include "AppleManifest.h" -#include -#include -#include -#include -#include -#include -#include - - -/* - * Copyright (c) 2003-2004,2011-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - - - -const int kLengthLength = 8; - - - -static void ConvertUInt64ToBytes (UInt64 length, UInt8* bytes) -{ - int i; - for (i = kLengthLength - 1; i >= 0; i--) - { - bytes[i] = length & 0xFF; - length >>= 8; - } -} - - - -static void WriteLengthAndUpdate (CFMutableDataRef data, UInt64 length, CFIndex location) -{ - // back patch the length of the list - secdebug ("manifest", "Length was %lld, patched at location %lld", length, (UInt64) location); - - UInt8 lengthBytes[kLengthLength]; - ConvertUInt64ToBytes (length, lengthBytes); - - CFRange range = {location, kLengthLength}; - CFDataReplaceBytes (data, range, lengthBytes, kLengthLength); -} - - - -static CFIndex GetCurrentLengthAndExtend (CFMutableDataRef data) -{ - CFIndex currentIndex = CFDataGetLength (data); - CFDataIncreaseLength (data, kLengthLength); - return currentIndex; -} - - - -static void AppendUInt16 (CFMutableDataRef data, UInt16 num) -{ - UInt8 n[2]; - n[0] = num >> 8; - n[1] = num & 0xFF; - CFDataAppendBytes (data, n, sizeof (n)); -} - - - -static void AppendUInt32 (CFMutableDataRef data, UInt32 num) -{ - UInt8 n[4]; - n[0] = (num >> 24) & 0xFF; - n[1] = (num >> 16) & 0xFF; - n[2] = (num >> 8) & 0xFF; - n[3] = num & 0xFF; - CFDataAppendBytes (data, n, sizeof (n)); -} - - - -static void AppendUInt64 (CFMutableDataRef data, UInt64 num) -{ - UInt8 n[8]; - n[0] = (num >> 56) & 0xFF; - n[1] = (num >> 48) & 0xFF; - n[2] = (num >> 40) & 0xFF; - n[3] = (num >> 32) & 0xFF; - n[4] = (num >> 24) & 0xFF; - n[5] = (num >> 16) & 0xFF; - n[6] = (num >> 8) & 0xFF; - n[7] = num & 0xFF; - - CFDataAppendBytes (data, n, sizeof (n)); -} - - - -static void WriteFileSystemItemHeader (CFMutableDataRef data, const FileSystemEntryItem *fsi) -{ - // write the name - const char* name = fsi->GetName (); - secdebug ("manifest", "\tAdding header for %s", name); - uint16_t len = (uint16_t)strlen (name); - AppendUInt16 (data, len); - CFDataAppendBytes (data, (UInt8*) name, len); - AppendUInt32 (data, fsi->GetUID ()); - AppendUInt32 (data, fsi->GetGID ()); - AppendUInt32 (data, fsi->GetMode ()); -} - - - -AppleManifest::AppleManifest () -{ -} - - - -AppleManifest::~AppleManifest () -{ - // release our interest in the signers - int signerCount = (int)mSignerList.size (); - - int i; - for (i = 0; i < signerCount; ++i) - { - CFRelease (mSignerList[i]); - } -} - - - -void AppleManifest::AddDirectoryToManifest (CFMutableDataRef manifest, ManifestDirectoryItem* directory) -{ - secdebug ("manifest", "Adding directory %s to manifest", directory->GetName ()); - - CFIndex currentIndex = GetCurrentLengthAndExtend (manifest); - AppendUInt16 (manifest, (UInt16) kManifestDirectoryItemType); - - WriteFileSystemItemHeader (manifest, directory); - - AddManifestItemListToManifest (manifest, directory->GetItemList ()); - - WriteLengthAndUpdate (manifest, CFDataGetLength (manifest) - currentIndex, currentIndex); -} - - - -void AppleManifest::AddFileToManifest (CFMutableDataRef manifest, ManifestFileItem* file) -{ - CFIndex currentIndex = GetCurrentLengthAndExtend (manifest); - AppendUInt16 (manifest, (UInt16) kManifestFileItemType); - - WriteFileSystemItemHeader (manifest, file); - - int numForks = file->GetNumberOfForks (); - AppendUInt16 (manifest, (UInt16) numForks); - - int i; - // write the file lengths - for (i = 0; i < numForks; ++i) - { - size_t length; - length = file->GetForkLength (i); - AppendUInt64 (manifest, length); - } - - // write the digests - for (i = 0; i < numForks; ++i) - { - void* sha1Digest; - size_t size; - file->GetItemRepresentation (i, sha1Digest, size); - CFDataAppendBytes (manifest, (UInt8*) sha1Digest, size); - } - - WriteLengthAndUpdate (manifest, CFDataGetLength (manifest) - currentIndex, currentIndex); -} - - - -void AppleManifest::AddSymLinkToManifest (CFMutableDataRef manifest, ManifestSymLinkItem* file) -{ - CFIndex currentIndex = GetCurrentLengthAndExtend (manifest); - AppendUInt16 (manifest, (UInt16) kManifestSymLinkItemType); - - WriteFileSystemItemHeader (manifest, file); - - const SHA1Digest* digest = file->GetDigest (); - CFDataAppendBytes (manifest, (const UInt8*) digest, kSHA1DigestSize); - - WriteLengthAndUpdate (manifest, CFDataGetLength (manifest) - currentIndex, currentIndex); -} - - - -void AppleManifest::AddOtherToManifest (CFMutableDataRef manifest, ManifestOtherItem* other) -{ - CFIndex currentIndex = GetCurrentLengthAndExtend (manifest); - AppendUInt16 (manifest, (UInt16) kManifestSymLinkItemType); - - WriteFileSystemItemHeader (manifest, other); - - WriteLengthAndUpdate (manifest, CFDataGetLength (manifest) - currentIndex, currentIndex); -} - - - -void AppleManifest::AddDataBlobToManifest (CFMutableDataRef manifest, ManifestDataBlobItem* item) -{ - CFIndex currentIndex = GetCurrentLengthAndExtend (manifest); - AppendUInt16 (manifest, (UInt16) kManifestDataBlobItemType); - - AppendUInt64 (manifest, (UInt64) item->GetLength ()); - const SHA1Digest* sha1Digest = item->GetDigest (); - CFDataAppendBytes (manifest, (UInt8*) sha1Digest, sizeof (SHA1Digest)); - - WriteLengthAndUpdate (manifest, CFDataGetLength (manifest) - currentIndex, currentIndex); -} - - - -void AppleManifest::AddManifestItemListToManifest (CFMutableDataRef data, ManifestItemList &itemList) -{ - // save the current position - CFIndex currentIndex = GetCurrentLengthAndExtend (data); - - unsigned i; - for (i = 0; i < itemList.size (); ++i) - { - ManifestItem* item = itemList[i]; - - switch (item->GetItemType ()) - { - case kManifestDataBlobItemType: - { - AddDataBlobToManifest (data, static_cast(item)); - break; - } - - case kManifestFileItemType: - { - AddFileToManifest (data, static_cast(item)); - break; - } - - case kManifestDirectoryItemType: - { - AddDirectoryToManifest (data, static_cast(item)); - break; - } - - case kManifestSymLinkItemType: - { - AddSymLinkToManifest (data, static_cast(item)); - break; - } - - case kManifestOtherType: - { - AddOtherToManifest (data, static_cast(item)); - break; - } - } - } - - WriteLengthAndUpdate (data, CFDataGetLength (data) - currentIndex, currentIndex); -} - - - -static const char gManifestHeader[] = {0x2F, 0xAA, 0x05, 0xB3, 0x64, 0x0E, 0x9D, 0x27}; // why these numbers? These were picked at random -static const char gManifestVersion[] = {0x01, 0x00, 0x00, 0x00}; - - - -void AppleManifest::CreateManifest (CFMutableDataRef manifest, ManifestInternal& internalManifest) -{ - // create the manifest header - CFDataAppendBytes (manifest, (UInt8*) gManifestHeader, sizeof (gManifestHeader)); - CFDataAppendBytes (manifest, (UInt8*) gManifestVersion, sizeof (gManifestVersion)); - AddManifestItemListToManifest (manifest, internalManifest.GetItemList ()); -} - - - -void AppleManifest::AddSignersToCmsMessage (SecCmsMessageRef cmsMessage, SecCmsSignedDataRef signedData) -{ - // add signers for each of our signers - int numSigners = (int)mSignerList.size (); - - int i; - for (i = 0; i < numSigners; ++i) - { - SecIdentityRef id = mSignerList[i]; - SecCmsSignerInfoRef signerInfo = SecCmsSignerInfoCreate (cmsMessage, id, SEC_OID_SHA1); - if (signerInfo == NULL) - { - SecCmsMessageDestroy (cmsMessage); - MacOSError::throwMe (errSecManifestCMSFailure); - } - - int result = SecCmsSignerInfoIncludeCerts (signerInfo, SecCmsCMCertChain, certUsageObjectSigner); - if (result != 0) - { - SecCmsMessageDestroy (cmsMessage); - MacOSError::throwMe (errSecManifestCMSFailure); - } - - SecCmsSignedDataAddSignerInfo (signedData, signerInfo); - } -} - - - -CFDataRef AppleManifest::Export (ManifestInternal& manifest) -{ - // there had better be at least one signer - if (mSignerList.size () == 0) - { - secdebug ("manifest", "No signers found"); - MacOSError::throwMe (errSecManifestNoSigners); - } - - // create a CFMutableDataRef to hold the manifest object - CFMutableDataRef data = CFDataCreateMutable (kCFAllocatorDefault, 0); - - // make the manifest - CreateManifest (data, manifest); - - // make the PKCS #7 wrapper - SecCmsMessageRef cmsMessage; - cmsMessage = SecCmsMessageCreate (NULL); - if (cmsMessage == NULL) // did something go wrong? - { - MacOSError::throwMe (errSecManifestCMSFailure); - } - - // create a signed data holder - SecCmsSignedDataRef signedData; - signedData = SecCmsSignedDataCreate (cmsMessage); - if (signedData == NULL) - { - SecCmsMessageDestroy (cmsMessage); - MacOSError::throwMe (errSecManifestCMSFailure); - } - - // link the signed data and the CMS message - SecCmsContentInfoRef contentInfo = SecCmsMessageGetContentInfo (cmsMessage); - - int result = SecCmsContentInfoSetContentSignedData (cmsMessage, contentInfo, signedData); - if (result != 0) - { - SecCmsMessageDestroy (cmsMessage); - MacOSError::throwMe (errSecManifestCMSFailure); - } - - // attach the content information from the signature to the data - contentInfo = SecCmsSignedDataGetContentInfo (signedData); - result = SecCmsContentInfoSetContentData (cmsMessage, contentInfo, NULL, false); - if (result != 0) - { - SecCmsMessageDestroy (cmsMessage); - MacOSError::throwMe (errSecManifestCMSFailure); - } - - AddSignersToCmsMessage (cmsMessage, signedData); - - // make an encoder context - SecArenaPoolRef arena; - result = SecArenaPoolCreate(1024, &arena); - if (result) - { - MacOSError::throwMe (errSecManifestCMSFailure); - } - - CSSM_DATA finalMessage = {0, NULL}; - SecCmsEncoderRef encoderContext; - result = SecCmsEncoderCreate (cmsMessage, NULL, NULL, &finalMessage, arena, NULL, NULL, NULL, NULL, NULL, NULL, &encoderContext); - if (result) - { - MacOSError::throwMe (errSecManifestCMSFailure); - } - - result = SecCmsEncoderUpdate (encoderContext, CFDataGetBytePtr (data), CFDataGetLength (data)); - if (result != 0) - { - SecCmsMessageDestroy (cmsMessage); - MacOSError::throwMe (errSecManifestCMSFailure); - } - - result = SecCmsEncoderFinish (encoderContext); - if (result != 0) - { - MacOSError::throwMe (errSecManifestCMSFailure); - } - - // create a CFData from the results - CFDataRef retData = CFDataCreate (kCFAllocatorDefault, (UInt8*) finalMessage.Data, finalMessage.Length); - - SecArenaPoolFree(arena, false); - SecCmsMessageDestroy (cmsMessage); - - CFRelease (data); - - return retData; -} - - - -static u_int64_t ReconstructUInt64 (uint32& finger, const uint8* data) -{ - unsigned i; - u_int64_t r = 0; - - for (i = 0; i < sizeof (u_int64_t); ++i) - { - r = (r << 8) | data[finger++]; - } - - return r; -} - - - -static u_int32_t ReconstructUInt32 (uint32& finger, const uint8* data) -{ - unsigned i; - u_int32_t r = 0; - - for (i = 0; i < sizeof (u_int32_t); ++i) - { - r = (r << 8) | data[finger++]; - } - - return r; -} - - - -static u_int16_t ReconstructUInt16 (uint32& finger, const uint8* data) -{ - unsigned i; - u_int16_t r = 0; - - for (i = 0; i < sizeof (u_int16_t); ++i) - { - r = (r << 8) | data[finger++]; - } - - return r; -} - - - -static void ReconstructFileSystemHeader (uint32& finger, const uint8* data, FileSystemEntryItem* item) -{ - // get the number of bytes for the name - u_int16_t length = ReconstructUInt16 (finger, data); - char name[length + 1]; - - // make a c-string for the name - memcpy (name, data + finger, length); - name[length] = 0; - item->SetName (name); - - secdebug ("manifest", " File item name is %s", name); - - finger += length; - - uid_t uid = (uid_t) ReconstructUInt32 (finger, data); - gid_t gid = (gid_t) ReconstructUInt32 (finger, data); - mode_t mode = (mode_t) ReconstructUInt32 (finger, data); - - secdebug ("manifest", " File item uid is %d", uid); - secdebug ("manifest", " File item gid is %d", gid); - secdebug ("manifest", " File item mode is %d", mode); - - item->SetUID (uid); - item->SetGID (gid); - item->SetMode (mode); -} - - - -static void ParseItemHeader (uint32 &finger, const uint8* data, ManifestItemType &itemType, u_int64_t &end) -{ - u_int64_t start = finger; - u_int64_t length = ReconstructUInt64 (finger, data); - itemType = (ManifestItemType) ReconstructUInt16 (finger, data); - end = start + length; -} - - - -void AppleManifest::ReconstructDataBlob (uint32 &finger, const uint8* data, ManifestDataBlobItem*& item) -{ - secdebug ("manifest", "Reconstructing data blob."); - item = new ManifestDataBlobItem (); - u_int64_t length = ReconstructUInt64 (finger, data); - item->SetLength ((size_t)length); - item->SetDigest ((SHA1Digest*) (data + finger)); - finger += kSHA1DigestSize; -} - - - -void AppleManifest::ReconstructDirectory (uint32 &finger, const uint8* data, ManifestDirectoryItem*& directory) -{ - // make the directory - secdebug ("manifest", "Reconstructing directory."); - directory = new ManifestDirectoryItem (); - ReconstructFileSystemHeader (finger, data, directory); - - ReconstructManifestItemList (finger, data, directory->GetItemList ()); -} - - - -void AppleManifest::ReconstructFile (uint32& finger, const uint8* data, ManifestFileItem *& file) -{ - secdebug ("manifest", "Reconstructing file."); - // make the file - file = new ManifestFileItem (); - ReconstructFileSystemHeader (finger, data, file); - - u_int16_t numForks = ReconstructUInt16 (finger, data); - file->SetNumberOfForks (numForks); - - // reconstruct the lengths - u_int16_t n; - for (n = 0; n < numForks; ++n) - { - u_int64_t length = ReconstructUInt64 (finger, data); - file->SetForkLength (n, (size_t) length); - } - - // reconstruct the digests - for (n = 0; n < numForks; ++n) - { - file->SetItemRepresentation (n, data + finger, kSHA1DigestSize); - finger += kSHA1DigestSize; - } -} - - - -void AppleManifest::ReconstructSymLink (uint32& finger, const uint8* data, ManifestSymLinkItem*& file) -{ - secdebug ("manifest", "Reconstructing symlink."); - file = new ManifestSymLinkItem (); - ReconstructFileSystemHeader (finger, data, file); - - file->SetDigest ((const SHA1Digest*) (data + finger)); - finger += kSHA1DigestSize; -} - - - -void AppleManifest::ReconstructOther (uint32& finger, const uint8* data, ManifestOtherItem*& other) -{ - secdebug ("manifest", "Reconstructing other."); - other = new ManifestOtherItem (); - ReconstructFileSystemHeader (finger, data, other); -} - - - -void AppleManifest::ReconstructManifestItemList (uint32 &finger, const uint8* data, ManifestItemList &itemList) -{ - uint32 start = finger; - u_int64_t length = ReconstructUInt64 (finger, data); -#warning Casting from uint64 to uint32, this is ripe for overflow. - uint32 end = (uint32)(start + length); - - while (finger < end) - { - u_int64_t itemEnd; - ManifestItemType itemType; - ParseItemHeader (finger, data, itemType, itemEnd); - - switch (itemType) - { - case kManifestFileItemType: - { - ManifestFileItem* file; - ReconstructFile (finger, data, file); - itemList.push_back (file); - } - break; - - case kManifestDirectoryItemType: - { - ManifestDirectoryItem* directory; - ReconstructDirectory (finger, data, directory); - itemList.push_back (directory); - } - break; - - case kManifestSymLinkItemType: - { - ManifestSymLinkItem* symLink; - ReconstructSymLink (finger, data, symLink); - itemList.push_back (symLink); - } - break; - - case kManifestOtherType: - { - ManifestOtherItem* other; - ReconstructOther (finger, data, other); - itemList.push_back (other); - } - break; - - case kManifestDataBlobItemType: - { - ManifestDataBlobItem* item; - ReconstructDataBlob (finger, data, item); - itemList.push_back (item); - } - break; - } - - if (finger != itemEnd) - { - MacOSError::throwMe (errSecManifestDamaged); - } - } -} - - - -void AppleManifest::ReconstructManifest (uint8* data, uint32 length, ManifestInternal& manifest) -{ - uint32 finger = 0; - - // make sure the passed-in header starts with our magic number - if (memcmp (data, gManifestHeader, sizeof (gManifestHeader)) != 0) - { - MacOSError::throwMe (errSecManifestDamaged); - } - - finger += sizeof (gManifestHeader); - - // for now, the version had better be 0x01000000 - if (memcmp (data + finger, gManifestVersion, sizeof (gManifestVersion)) != 0) - { - MacOSError::throwMe (errSecManifestDamaged); - } - - finger += sizeof (gManifestVersion); - - ReconstructManifestItemList (finger, data, manifest.GetItemList ()); -} - - - -SecCmsMessageRef AppleManifest::GetCmsMessageFromData (CFDataRef data) -{ - // setup decoding - SecCmsDecoderRef decoderContext; - int result = SecCmsDecoderCreate (NULL, NULL, NULL, NULL, NULL, NULL, NULL, &decoderContext); - if (result) - { - MacOSError::throwMe (errSecManifestCMSFailure); - } - - result = SecCmsDecoderUpdate (decoderContext, CFDataGetBytePtr (data), CFDataGetLength (data)); - if (result) - { - SecCmsDecoderDestroy(decoderContext); - MacOSError::throwMe (errSecManifestCMSFailure); - } - - SecCmsMessageRef message; - result = SecCmsDecoderFinish (decoderContext, &message); - if (result) - { - MacOSError::throwMe (errSecManifestCMSFailure); - } - - return message; -} - - - -void AppleManifest::Verify (CFDataRef data, SecManifestTrustSetupCallback setupCallback, void* setupContext, - SecManifestTrustEvaluateCallback evaluateCallback, void* evaluateContext, - SecPolicyRef policy, ManifestInternal *manifest) -{ - SecCmsMessageRef cmsMessage = NULL; - - try - { - cmsMessage = GetCmsMessageFromData (data); - - SecPolicySearchRef search; - OSStatus result; - - SecPolicyRef originalPolicy = policy; - - if (policy == NULL) - { - // get a basic SecPolicy - result = SecPolicySearchCreate (CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &search); - MacOSError::check (result); - - result = SecPolicySearchCopyNext (search, &policy); - if (result != errSecSuccess) - { - MacOSError::throwMe (errSecManifestNoPolicy); - } - - CFRelease (search); - } - - // process the results - int contentLevelCount = SecCmsMessageContentLevelCount (cmsMessage); - SecCmsSignedDataRef signedData; - - int i = 0; - while (i < contentLevelCount) - { - SecCmsContentInfoRef contentInfo = SecCmsMessageContentLevel (cmsMessage, i++); - SECOidTag contentTypeTag = SecCmsContentInfoGetContentTypeTag (contentInfo); - - if (contentTypeTag != SEC_OID_PKCS7_SIGNED_DATA) - { - continue; - } - - signedData = (SecCmsSignedDataRef) SecCmsContentInfoGetContent (contentInfo); - if (signedData == NULL) - { - MacOSError::throwMe (errSecManifestDidNotVerify); - } - - // import the certificates found in the cms message - result = SecCmsSignedDataImportCerts (signedData, NULL, certUsageObjectSigner, true); - if (result != 0) - { - MacOSError::throwMe (result); - } - - int numberOfSigners = SecCmsSignedDataSignerInfoCount (signedData); - int j; - - if (numberOfSigners == 0) // no signers? This is a possible attack - { - MacOSError::throwMe (errSecManifestNoSignersFound); - } - - for (j = 0; j < numberOfSigners; ++j) - { - SecTrustResultType resultType; - SecTrustRef trustRef = NULL; - - try - { - result = SecCmsSignedDataVerifySignerInfo (signedData, j, NULL, policy, &trustRef); - - if (result != 0) - { - MacOSError::throwMe (result); - } - - SecManifestTrustCallbackResult tcResult = setupCallback (trustRef, setupContext); - switch (tcResult) - { - case kSecManifestDoNotVerify: - continue; - - case kSecManifestSignerVerified: - continue; - - case kSecManifestFailed: - MacOSError::throwMe (errSecManifestDidNotVerify); - - case kSecManifestContinue: - break; - } - - result = SecTrustEvaluate (trustRef, &resultType); - if (result != errSecSuccess) - { - MacOSError::throwMe (result); - } - - if (resultType != kSecTrustResultProceed) - { - if (evaluateCallback (trustRef, resultType, evaluateContext) != kSecManifestSignerVerified) - { - MacOSError::throwMe (errSecManifestDidNotVerify); - } - } - - CFRelease (trustRef); - } - catch (...) - { - if (trustRef != NULL) - { - CFRelease (trustRef); - } - - throw; - } - } - } - - if (manifest != NULL) - { - CSSM_DATA_PTR message = SecCmsMessageGetContent (cmsMessage); - ReconstructManifest (message->Data, (uint32)message->Length, *manifest); - } - - SecCmsMessageDestroy (cmsMessage); - if (originalPolicy == NULL) - { - CFRelease (policy); - } - } - catch (...) - { - if (cmsMessage != NULL) - { - SecCmsMessageDestroy (cmsMessage); - } - - throw; - } -} - - - -void AppleManifest::AddSigner (SecIdentityRef identityRef) -{ - CFRetain (identityRef); - mSignerList.push_back (identityRef); -} -