]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_manifest/lib/AppleManifest.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_manifest / lib / AppleManifest.cpp
diff --git a/OSX/libsecurity_manifest/lib/AppleManifest.cpp b/OSX/libsecurity_manifest/lib/AppleManifest.cpp
new file mode 100644 (file)
index 0000000..31db942
--- /dev/null
@@ -0,0 +1,858 @@
+#include "AppleManifest.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/SecCmsContentInfo.h>
+#include <Security/SecCmsDecoder.h>
+#include <Security/SecCmsEncoder.h>
+#include <Security/SecCmsMessage.h>
+#include <Security/SecCmsSignedData.h>
+#include <Security/SecCmsSignerInfo.h>
+
+
+/*
+ * 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<ManifestDataBlobItem*>(item));
+                               break;
+                       }
+                       
+                       case kManifestFileItemType:
+                       {
+                               AddFileToManifest (data, static_cast<ManifestFileItem*>(item));
+                               break;
+                       }
+                       
+                       case kManifestDirectoryItemType:
+                       {
+                               AddDirectoryToManifest (data, static_cast<ManifestDirectoryItem*>(item));
+                               break;
+                       }
+                       
+                       case kManifestSymLinkItemType:
+                       {
+                               AddSymLinkToManifest (data, static_cast<ManifestSymLinkItem*>(item));
+                               break;
+                       }
+                       
+                       case kManifestOtherType:
+                       {
+                               AddOtherToManifest (data, static_cast<ManifestOtherItem*>(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);
+}
+