AppleManifest.cpp   [plain text]


#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 Apple Computer, 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);
	int len = 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 = 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 = 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_int64_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_int64_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 (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);
	uint32 end = 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 != noErr)
			{
				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 != noErr)
					{
						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, 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);
}