1//
2//  OTAServiceApp.m
3//  Security
4//
5//  Created by local on 2/11/13.
6//
7//
8
9
10#import "OTAServiceApp.h"
11
12#import <TargetConditionals.h>
13#import <Security/Security.h>
14#import <Security/SecPolicyPriv.h>
15#import <Security/SecTrustPriv.h>
16#import <syslog.h>
17#import <xpc/xpc.h>
18#import <MobileAsset/MobileAsset.h>
19#import <Security/Security.h>
20#import <Security/SecCMS.h>
21#import <Security/SecCmsMessage.h>
22#import <Security/SecCmsDecoder.h>
23#import <Security/SecCmsContentInfo.h>
24#import <Security/SecCmsSignedData.h>
25#import <CommonCrypto/CommonDigest.h>
26#import <CommonNumerics/CommonBaseXX.h>
27#import <ManagedConfiguration/MCProfileConnection.h>
28#import <MobileGestalt.h>
29
30#if !TARGET_IPHONE_SIMULATOR
31#import <BackgroundTaskAgent/BackgroundTaskAgent.h>
32#endif
33
34#import <sys/types.h>
35#import <pwd.h>
36#import <stdlib.h>
37#import <unistd.h>
38#import <stdio.h>
39#import <grp.h>
40#import <sys/stat.h>
41#import <syslog.h>
42
43#define CFReleaseSafe(CF) { CFTypeRef _cf = (CF); if (_cf) {  CFRelease(_cf); } }
44#define CFReleaseNull(CF) { CFTypeRef _cf = (CF); if (_cf) {  (CF) = NULL; CFRelease(_cf); } }
45
46//#define VERBOSE_LOGGING 1
47
48#if VERBOSE_LOGGING
49
50static void OTAPKI_LOG(const char* sz, ...)
51{
52	va_list va;
53    va_start(va, sz);
54
55    FILE* fp = fopen("/tmp/OTAPKITool.log", "a");
56    if (NULL != fp)
57    {
58        vfprintf(fp, sz, va);
59        fclose(fp);
60    }
61    va_end(va);
62}
63
64#else
65
66#define OTAPKI_LOG(sz, ...)
67
68#endif
69
70//#define NEW_LOCATION 1
71
72
73
74/* ==========================================================================
75	The following are a set of string constants used by this program.  
76	
77	kBaseAssetDirectoryPath -	This is the full path on the device that 
78								will contain the Assets directory.  This
79								directory was chosen because it is owned
80								by securityd
81								
82	kkManifestFileName - 		The file name of the manifest file for the
83								OTA PKI trust asset
84								
85	kAssetVersionFileName - 	The file name of the plist file in the asset
86								that contains the version number of this 
87								OTA PKI trust asset. It is a plist that is a 
88								dictionary with a single key with a single 
89								key value pair that has the version number 
90								of the asset.  This is used to ensure against
91								anti-replay.
92								
93	kBlockKeyFileName - 		The file name of the asset file that contains
94								blocked keys.  Any certificate with these keys
95								will be marked as not being trusted.
96 
97    kGrayListedKeysFileName -   The file name of the asset file that contains
98                                gray listed keys.  If a chain has any of these
99                                keys, than the chain will still be approved but
100                                an entry will be added to the details dictionary
101                                noting that the key was gray listed
102    
103								
104	kEVRootsFileName - 			The file name of the asset file that contains
105								the list of EV OIDS and their corresponding
106								certificates.  This file sets which certs will
107								be considered to be EV.
108								
109	kCertsIndexFileName - 		The file name of the asset file that contains
110								a hash table of offsets into the cert table
111								file.  This is used to look up anchor certs.
112								
113	kCertsTableFileName - 		The file name of the asset file that contains
114								all of the anchor certificates.  The 
115								kCertsIndexFileName file is used to find the 
116								correct offset in this file to retrieve a
117								specific anchor certificate.
118								
119	kVersionNumberKey - 		The dictionary key for the kAssetVersionFileName
120								file to get the version number
121 
122    kVersionDirectoryNamePrefix - 
123                                The directory name prefix for all of the 
124                                asset directorys
125 
126    kPKITrustDataAssetType -    The asset identifier of the OTA PKI asset
127 
128    
129========================================================================== */
130
131#if NEW_LOCATION
132static const NSString* kBaseAssetDirectoryPath = @"/var/OTAPKI";
133#else
134static const NSString* kBaseAssetDirectoryPath = @"/var/Keychains";
135#endif
136
137static const NSString* kManifestFileName = @"manifest.data";
138static const NSString* kAssetVersionFileName =  @"AssetVersion.plist";
139static const NSString* kAppleESCertificatesName = @"AppleESCertificates.plist";
140static const NSString* kBlockKeyFileName = @"Blocked.plist";
141static const NSString* kGrayListedKeysFileName = @"GrayListedKeys.plist";
142static const NSString* kEVRootsFileName = @"EVRoots.plist";
143static const NSString* kCertsIndexFileName = @"certsIndex.data";
144static const NSString* kCertsTableFileName = @"certsTable.data";
145static const NSString* kVersionNumberKey = @"VersionNumber";
146static const NSString* kAssetDirectoryName = @"Assets";
147static const NSString* kAssetDirectoryUser = @"_securityd";
148static const NSString* kAssetDirectoryGroup = @"wheel";
149#if NEW_LOCATION
150static const unsigned long kAssetDirectoryPermission = S_IRWXU | S_IRWXG | S_IRWXO;
151#else
152static const unsigned long kAssetDirectoryPermission = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
153#endif
154static const NSString* kVersionDirectoryNamePrefix = @"Version_";
155static const NSString* kPKITrustDataAssetType =@"com.apple.MobileAsset.PKITrustServices.PKITrustData";
156
157const char *kOTAPKIAssetToolActivity = "com.apple.OTAPKIAssetTool.asset-check";
158
159static const UInt8 kApplePKISettingsRootCACert[] = {
160	0x30, 0x82, 0x07, 0xca, 0x30, 0x82, 0x05, 0xb2, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x4e,
161	0xa1, 0x31, 0xe7, 0xca, 0x50, 0xb8, 0x97, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
162	0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00, 0x30, 0x81, 0x84, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55,
163	0x04, 0x03, 0x0c, 0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65,
164	0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
165	0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
166	0x69, 0x74, 0x79, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70,
167	0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
168	0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x13, 0x30, 0x11, 0x06,
169	0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e,
170	0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x30, 0x1e, 0x17,
171	0x0d, 0x31, 0x33, 0x30, 0x36, 0x32, 0x34, 0x32, 0x33, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x17, 0x0d,
172	0x34, 0x33, 0x30, 0x36, 0x31, 0x37, 0x32, 0x33, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x30, 0x81, 0x84,
173	0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65,
174	0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f,
175	0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
176	0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03,
177	0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
178	0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
179	0x74, 0x79, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70,
180	0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
181	0x13, 0x02, 0x55, 0x53, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
182	0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a,
183	0x02, 0x82, 0x02, 0x01, 0x00, 0xce, 0x15, 0xf7, 0x6f, 0xd8, 0x42, 0x0c, 0x6f, 0x45, 0xb4, 0x04,
184	0x59, 0x24, 0xcb, 0x70, 0x88, 0x84, 0x77, 0xa1, 0x91, 0x54, 0xf4, 0x87, 0x61, 0xb3, 0xd3, 0xfc,
185	0xbe, 0xb6, 0x05, 0x3c, 0xb9, 0xb7, 0x7d, 0x7c, 0xbc, 0x0b, 0xe8, 0x87, 0x07, 0xcf, 0x20, 0xbe,
186	0xaa, 0xeb, 0x24, 0xc5, 0xe4, 0x5c, 0xcd, 0xcb, 0x89, 0x9f, 0x7a, 0xea, 0xb4, 0x5d, 0x3b, 0x29,
187	0x6c, 0xba, 0x4d, 0x15, 0xfb, 0x59, 0xd0, 0x5a, 0xea, 0x41, 0x4e, 0x0d, 0x1d, 0xf7, 0x66, 0x77,
188	0xa2, 0x96, 0x56, 0xed, 0xd1, 0x16, 0x7b, 0xea, 0xf5, 0x60, 0xdf, 0x32, 0x9c, 0xa9, 0xfd, 0xbf,
189	0xb8, 0x34, 0x6f, 0x57, 0x17, 0xe6, 0x04, 0x37, 0x71, 0x07, 0xc0, 0xe9, 0x0f, 0x3c, 0xed, 0x4f,
190	0x31, 0x87, 0x05, 0xa4, 0xed, 0xab, 0xac, 0xd6, 0x50, 0x05, 0x5b, 0xca, 0xd3, 0xf9, 0xd6, 0xaa,
191	0xaa, 0x88, 0x57, 0x66, 0xf6, 0x6d, 0x8d, 0x4b, 0x71, 0x29, 0xd4, 0x3d, 0x1d, 0xbc, 0x82, 0x6e,
192	0x81, 0xe9, 0x19, 0xf5, 0xe1, 0x12, 0x9f, 0x47, 0xdb, 0x5c, 0xed, 0x88, 0xba, 0x51, 0xe7, 0x3a,
193	0xa0, 0x77, 0x2d, 0xe6, 0xcc, 0xb4, 0x34, 0xdf, 0xad, 0xbd, 0x7b, 0xf8, 0xa7, 0x79, 0x51, 0x2d,
194	0xe6, 0xc2, 0xee, 0xd2, 0x96, 0xfa, 0x60, 0x60, 0x32, 0x40, 0x41, 0x37, 0x12, 0xeb, 0x63, 0x99,
195	0x3d, 0xf3, 0x21, 0xbe, 0xdf, 0xa1, 0x77, 0xe6, 0x81, 0xa9, 0x99, 0x0c, 0x4b, 0x43, 0x0c, 0x05,
196	0x6a, 0x6b, 0x8f, 0x05, 0x02, 0xd9, 0x43, 0xab, 0x72, 0x76, 0xca, 0xa7, 0x75, 0x63, 0x85, 0xe3,
197	0xa5, 0x5c, 0xc0, 0xd6, 0xd4, 0x1c, 0xeb, 0xac, 0x2c, 0x9a, 0x15, 0x6b, 0x4e, 0x99, 0x74, 0x7d,
198	0xd2, 0x69, 0x9f, 0xa8, 0xf7, 0x65, 0xde, 0xeb, 0x36, 0x85, 0xd5, 0x7e, 0x4a, 0x7a, 0x8a, 0xeb,
199	0x7c, 0xcd, 0x43, 0x9e, 0x05, 0xdb, 0x34, 0xc3, 0x69, 0xbd, 0xc2, 0xe7, 0xfb, 0xa0, 0x43, 0xb3,
200	0xd7, 0x15, 0x28, 0x8a, 0x91, 0xce, 0xd7, 0xa7, 0xa4, 0xcc, 0xf4, 0x1b, 0x37, 0x33, 0x76, 0xc4,
201	0x58, 0xb9, 0x2d, 0x89, 0xe2, 0xb6, 0x2c, 0x56, 0x10, 0x96, 0xcc, 0xa6, 0x07, 0x79, 0x11, 0x7d,
202	0x26, 0xd2, 0x85, 0x22, 0x19, 0x20, 0xb7, 0xef, 0xc3, 0xd9, 0x4e, 0x18, 0xf3, 0xaa, 0x05, 0xce,
203	0x87, 0x99, 0xde, 0x76, 0x90, 0x08, 0x74, 0xac, 0x61, 0x31, 0xf8, 0x51, 0xa0, 0xc9, 0x70, 0xfc,
204	0xb9, 0x22, 0xfe, 0xd2, 0x0d, 0xc8, 0x49, 0x64, 0x00, 0xe4, 0xf1, 0x53, 0xfd, 0xa1, 0xe6, 0xff,
205	0x8e, 0xd6, 0xde, 0x9e, 0xcc, 0x3d, 0x37, 0x3a, 0x10, 0x62, 0x59, 0xb2, 0x34, 0x8a, 0x1d, 0xf7,
206	0x9e, 0xa0, 0xbb, 0xf4, 0x53, 0xd9, 0xb8, 0x18, 0x88, 0x12, 0x5c, 0x92, 0x0d, 0xc9, 0x94, 0x7f,
207	0x24, 0xb9, 0x9f, 0xda, 0x07, 0xb6, 0x79, 0x77, 0x09, 0xa3, 0x29, 0x3a, 0x70, 0x63, 0x3b, 0x22,
208	0x42, 0x14, 0xd0, 0xf9, 0x7b, 0x90, 0x52, 0x2b, 0x3f, 0x7f, 0xb7, 0x41, 0x20, 0x0d, 0x7e, 0x70,
209	0xd7, 0x88, 0x36, 0xa2, 0xe9, 0x81, 0x77, 0xf4, 0xb0, 0x15, 0x43, 0x9c, 0x5f, 0x4d, 0x3e, 0x4f,
210	0x83, 0x79, 0x06, 0x73, 0x7a, 0xe7, 0xcb, 0x79, 0x1d, 0xec, 0xa3, 0xce, 0x93, 0x5c, 0x68, 0xbf,
211	0x5a, 0xe6, 0x4c, 0x23, 0x86, 0x41, 0x7f, 0xb4, 0xfc, 0xd0, 0x2c, 0x1b, 0x64, 0x39, 0x64, 0xb7,
212	0xd2, 0x1d, 0xd0, 0x2d, 0x16, 0x77, 0xfe, 0x4d, 0xad, 0xf0, 0x4f, 0x38, 0xb3, 0xf9, 0x5a, 0xee,
213	0x0e, 0x1d, 0xb6, 0xf9, 0x3f, 0xba, 0x77, 0x5a, 0x20, 0xd2, 0x74, 0x1a, 0x4b, 0x5a, 0xaf, 0x62,
214	0xb5, 0xd3, 0xef, 0x37, 0x49, 0xfe, 0x1e, 0xcd, 0xb5, 0xba, 0xb5, 0xa6, 0x46, 0x7b, 0x38, 0x63,
215	0x62, 0x3c, 0x18, 0x7d, 0x57, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x02, 0x3c, 0x30, 0x82,
216	0x02, 0x38, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x35, 0x07, 0x82,
217	0xfe, 0x0e, 0x8f, 0xf5, 0xa0, 0x7c, 0x2e, 0xf9, 0x65, 0x7b, 0xa8, 0x48, 0xe8, 0x8f, 0x61, 0xb6,
218	0x1c, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
219	0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x35,
220	0x07, 0x82, 0xfe, 0x0e, 0x8f, 0xf5, 0xa0, 0x7c, 0x2e, 0xf9, 0x65, 0x7b, 0xa8, 0x48, 0xe8, 0x8f,
221	0x61, 0xb6, 0x1c, 0x30, 0x82, 0x01, 0xd3, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x82, 0x01, 0xca,
222	0x30, 0x82, 0x01, 0xc6, 0x30, 0x82, 0x01, 0xc2, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x63,
223	0x64, 0x05, 0x01, 0x30, 0x82, 0x01, 0xb3, 0x30, 0x82, 0x01, 0x78, 0x06, 0x08, 0x2b, 0x06, 0x01,
224	0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x82, 0x01, 0x6a, 0x1e, 0x82, 0x01, 0x66, 0x00, 0x52, 0x00,
225	0x65, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00,
226	0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00,
227	0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00,
228	0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x62, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00,
229	0x6e, 0x00, 0x79, 0x00, 0x20, 0x00, 0x70, 0x00, 0x61, 0x00, 0x72, 0x00, 0x74, 0x00, 0x79, 0x00,
230	0x20, 0x00, 0x61, 0x00, 0x73, 0x00, 0x73, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x73, 0x00,
231	0x20, 0x00, 0x61, 0x00, 0x63, 0x00, 0x63, 0x00, 0x65, 0x00, 0x70, 0x00, 0x74, 0x00, 0x61, 0x00,
232	0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x74, 0x00,
233	0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00,
234	0x61, 0x00, 0x70, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x62, 0x00,
235	0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00,
236	0x61, 0x00, 0x72, 0x00, 0x64, 0x00, 0x20, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6d, 0x00,
237	0x73, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x63, 0x00, 0x6f, 0x00,
238	0x6e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x73, 0x00,
239	0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x65, 0x00, 0x2c, 0x00,
240	0x20, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00,
241	0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x6c, 0x00,
242	0x69, 0x00, 0x63, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00,
243	0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00,
244	0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x70, 0x00, 0x72, 0x00,
245	0x61, 0x00, 0x63, 0x00, 0x74, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73, 0x00,
246	0x74, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00,
247	0x73, 0x00, 0x2e, 0x30, 0x35, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16,
248	0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x70, 0x70, 0x6c,
249	0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
250	0x65, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
251	0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
252	0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x6f, 0x8a,
253	0xb7, 0x35, 0x73, 0x5a, 0xc5, 0x34, 0xf7, 0x8c, 0xf0, 0xd1, 0x4a, 0x17, 0x52, 0x1c, 0x70, 0xf0,
254	0xe0, 0x53, 0xb4, 0x16, 0xde, 0x81, 0xda, 0x2a, 0xa4, 0xf9, 0x5b, 0x0e, 0xa6, 0x17, 0x86, 0x52,
255	0xc6, 0x70, 0x73, 0xf3, 0x3f, 0x1c, 0x87, 0x94, 0xdd, 0xfe, 0x02, 0x0b, 0x85, 0xc9, 0xb9, 0xcf,
256	0x15, 0x91, 0x05, 0x2e, 0x7e, 0xeb, 0xe6, 0xce, 0x0e, 0x4e, 0xd1, 0xf7, 0xe2, 0xd7, 0xf4, 0x60,
257	0xd2, 0xfc, 0x1d, 0xbf, 0xad, 0x61, 0x28, 0xf8, 0x53, 0x31, 0xb3, 0x92, 0xef, 0xa4, 0x05, 0x34,
258	0x97, 0x57, 0x97, 0x56, 0x3b, 0x12, 0x20, 0x2d, 0x88, 0x76, 0x81, 0x0e, 0x77, 0x85, 0xf1, 0x37,
259	0xc6, 0x19, 0x8b, 0x23, 0xc2, 0x42, 0x55, 0x40, 0xc9, 0x91, 0x5c, 0x78, 0xc5, 0xe6, 0x77, 0xfe,
260	0x72, 0x5f, 0xb2, 0x2c, 0x00, 0xf2, 0xe6, 0x8c, 0xcc, 0x02, 0x49, 0xd9, 0x78, 0x20, 0xae, 0xbd,
261	0x75, 0x61, 0x6a, 0xaa, 0xc5, 0x71, 0x3e, 0x5d, 0x02, 0xdf, 0xd2, 0x91, 0x5c, 0x0a, 0x85, 0xc9,
262	0x59, 0x7d, 0x4e, 0x89, 0x21, 0x59, 0x59, 0xe3, 0xc7, 0xdc, 0xff, 0x1e, 0x62, 0x1e, 0xb9, 0x62,
263	0x2c, 0x34, 0x49, 0x15, 0xd9, 0xdf, 0x47, 0x99, 0x39, 0xcc, 0x1a, 0x01, 0xc0, 0xda, 0x48, 0x44,
264	0xd4, 0x8b, 0xd3, 0x17, 0x7e, 0x39, 0xf9, 0x00, 0xe1, 0x2a, 0x46, 0xaa, 0x14, 0x22, 0xa1, 0x38,
265	0x09, 0x0b, 0xb7, 0x0c, 0x88, 0xa5, 0x73, 0xfd, 0xc4, 0x6b, 0xee, 0x07, 0xb4, 0x1b, 0xb3, 0x4a,
266	0xab, 0xae, 0xf6, 0xe7, 0x04, 0x61, 0x4b, 0x34, 0x7a, 0xe4, 0xff, 0xf9, 0x30, 0x28, 0x61, 0x92,
267	0x52, 0x58, 0x10, 0x15, 0x3a, 0x9f, 0x0a, 0xaf, 0x15, 0x29, 0x6c, 0x67, 0xc4, 0xb4, 0xcf, 0xe6,
268	0xf9, 0x46, 0x68, 0xe2, 0x2a, 0x97, 0x29, 0x16, 0xed, 0x1a, 0x9b, 0x9a, 0x45, 0x70, 0x3c, 0xf2,
269	0xdf, 0x29, 0x20, 0x9e, 0x33, 0x4b, 0x5b, 0x8d, 0xf6, 0x19, 0xec, 0x4b, 0xae, 0x1a, 0x2f, 0x53,
270	0x03, 0x9a, 0xfd, 0x68, 0x39, 0x58, 0xf7, 0x2e, 0x07, 0x9c, 0xf1, 0x3c, 0x1b, 0x47, 0x43, 0x19,
271	0x81, 0x0e, 0x0a, 0xbb, 0x84, 0xa0, 0xda, 0x87, 0xbc, 0x8a, 0x2a, 0xb7, 0x9c, 0xe1, 0xf9, 0xeb,
272	0x37, 0xb0, 0x11, 0x20, 0x7e, 0x4c, 0x11, 0x2e, 0x54, 0x30, 0xce, 0xaf, 0x63, 0xed, 0x6a, 0x63,
273	0x1f, 0x1e, 0x61, 0x62, 0x04, 0xf3, 0x3a, 0x5f, 0x26, 0x6c, 0x5c, 0xd7, 0xba, 0x4f, 0xf2, 0x61,
274	0x26, 0x29, 0x99, 0xea, 0x61, 0x84, 0x0d, 0x68, 0xa2, 0x5d, 0x9b, 0x5c, 0xe7, 0x86, 0x1d, 0xef,
275	0xf4, 0x6f, 0x3b, 0x6c, 0x67, 0xf0, 0x70, 0xe9, 0xc5, 0xdc, 0x0a, 0x9d, 0x0f, 0xdc, 0xcc, 0x0e,
276	0x7b, 0xf8, 0xc4, 0xee, 0x64, 0xe4, 0xd9, 0x3f, 0x14, 0xae, 0x8f, 0xc8, 0x18, 0x4d, 0xa1, 0xe4,
277	0x40, 0x2c, 0xe9, 0x13, 0xc6, 0xc1, 0xe0, 0xb9, 0x13, 0xbe, 0xd9, 0x93, 0x66, 0x56, 0x35, 0x5c,
278	0xc1, 0x38, 0x7d, 0xa1, 0xbb, 0x87, 0xa5, 0x90, 0x33, 0x4f, 0xea, 0xb6, 0x37, 0x19, 0x61, 0x81,
279	0x40, 0xba, 0xd7, 0x07, 0x69, 0x05, 0x15, 0x96, 0xe9, 0xde, 0x4f, 0x8a, 0x2b, 0x99, 0x5a, 0x17,
280	0x3f, 0x9f, 0xcf, 0x86, 0xf5, 0x37, 0x0a, 0xa1, 0x0e, 0x25, 0x65, 0x2d, 0x52, 0xce, 0x87, 0x10,
281	0x0f, 0x25, 0xc2, 0x1e, 0x0f, 0x71, 0x93, 0xb5, 0xc0, 0xb3, 0xb4, 0xd1, 0x65, 0xa8, 0xb4, 0xf6,
282	0xa5, 0x71, 0xad, 0x45, 0xdb, 0xdf, 0xec, 0xe3, 0x2a, 0x7e, 0x99, 0x96, 0x5a, 0x5d, 0x69, 0xfa,
283	0xdb, 0x13, 0x39, 0xb8, 0xf5, 0x58, 0xbb, 0x87, 0x69, 0x8d, 0x2c, 0x6d, 0x39, 0xff, 0x26, 0xce,
284	0x2c, 0xa8, 0x5a, 0x7e, 0x4b, 0x3f, 0xed, 0xac, 0x5f, 0xf0, 0xef, 0x48, 0xd3, 0xf8      
285};
286
287
288static const UInt8 kAppleTestPKISettingsRootCACert[] = {
289    0x30, 0x82, 0x05, 0xd7, 0x30, 0x82, 0x03, 0xbf, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x26,
290    0xfe, 0xf8, 0xda, 0x41, 0xf3, 0x61, 0x90, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
291    0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00, 0x30, 0x79, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04,
292    0x03, 0x0c, 0x24, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65, 0x74,
293    0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20,
294    0x54, 0x45, 0x53, 0x54, 0x49, 0x4e, 0x47, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b,
295    0x0c, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
296    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
297    0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20,
298    0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
299    0x53, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x34, 0x32, 0x32, 0x32, 0x30, 0x33, 0x31, 0x34,
300    0x36, 0x5a, 0x17, 0x0d, 0x34, 0x33, 0x30, 0x34, 0x31, 0x35, 0x32, 0x30, 0x33, 0x31, 0x34, 0x36,
301    0x5a, 0x30, 0x79, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x24, 0x41, 0x70,
302    0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
303    0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x54, 0x45, 0x53, 0x54, 0x49,
304    0x4e, 0x47, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70, 0x70,
305    0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
306    0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
307    0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
308    0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x30, 0x82, 0x02, 0x22,
309    0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
310    0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0x84, 0xbe, 0xc2,
311    0x69, 0x9b, 0xec, 0xd5, 0xde, 0x72, 0xf0, 0x4f, 0x78, 0x81, 0x10, 0xa9, 0x56, 0x59, 0x77, 0x9c,
312    0x46, 0x95, 0xd7, 0xb7, 0x0b, 0x77, 0x73, 0x02, 0xce, 0xf8, 0xaa, 0x32, 0x89, 0xee, 0xbe, 0xaa,
313    0x40, 0x53, 0xf9, 0x2d, 0x96, 0x08, 0xcd, 0x2a, 0xa4, 0x61, 0xd4, 0xfd, 0x7d, 0x67, 0x2a, 0x35,
314    0xc1, 0xfc, 0x43, 0xa4, 0x9c, 0xd0, 0xbd, 0xcd, 0x82, 0x27, 0xed, 0xa1, 0x1c, 0x2d, 0x9a, 0x62,
315    0xd5, 0x99, 0xbd, 0x74, 0xaa, 0xf3, 0xce, 0x78, 0xc6, 0x47, 0x07, 0x43, 0x04, 0x5b, 0xbc, 0x27,
316    0x5e, 0x26, 0x3e, 0x77, 0x90, 0x69, 0x7a, 0xf6, 0xe0, 0x8e, 0xaa, 0xdf, 0x96, 0x12, 0x2c, 0xb2,
317    0x8b, 0xb9, 0x7e, 0x17, 0xfe, 0xde, 0x99, 0x67, 0x9b, 0x50, 0x13, 0x5c, 0x8d, 0x15, 0x26, 0x0a,
318    0x9f, 0x08, 0x2f, 0x3f, 0x7c, 0x01, 0x2c, 0x3e, 0xa1, 0xba, 0xb1, 0x25, 0x33, 0xe5, 0xd9, 0x39,
319    0x37, 0xde, 0x06, 0x3a, 0x63, 0x48, 0xa0, 0x9d, 0x3b, 0xa5, 0x72, 0x46, 0xfb, 0x6e, 0xa2, 0xd4,
320    0x74, 0xe6, 0xf1, 0xc1, 0x69, 0xc8, 0x31, 0xff, 0x58, 0x84, 0x3a, 0xc2, 0x6b, 0x9a, 0x0d, 0x19,
321    0x76, 0xe4, 0xd4, 0x4d, 0x85, 0xbc, 0x84, 0xf0, 0x07, 0x75, 0x66, 0x5f, 0xd7, 0xea, 0xab, 0x9e,
322    0x46, 0xf2, 0x8a, 0x29, 0xab, 0x73, 0x57, 0xaf, 0x95, 0x4f, 0xc7, 0xf3, 0x3b, 0x55, 0xb4, 0x26,
323    0x57, 0x68, 0xe9, 0x5a, 0x34, 0xbb, 0xa9, 0x39, 0xb3, 0x57, 0x5f, 0x25, 0x93, 0xd6, 0x34, 0xb7,
324    0xd1, 0xc4, 0xd7, 0x70, 0xed, 0x30, 0xdb, 0x21, 0xc1, 0xcc, 0xdf, 0xed, 0xec, 0x37, 0xc5, 0xdc,
325    0x0b, 0xc9, 0x85, 0x46, 0x26, 0xa7, 0x51, 0xc8, 0xdd, 0xe6, 0x47, 0xfc, 0x37, 0xd6, 0x73, 0x6f,
326    0x91, 0x3d, 0xef, 0xd8, 0xa4, 0xa5, 0x08, 0x32, 0x8c, 0xae, 0x8f, 0x57, 0xf7, 0x99, 0x48, 0xef,
327    0x81, 0x44, 0xac, 0x80, 0x42, 0x57, 0x9f, 0x64, 0x77, 0x40, 0x2a, 0xec, 0x03, 0x21, 0x79, 0x01,
328    0x0b, 0x87, 0xc3, 0x9d, 0x22, 0xc9, 0xc0, 0x69, 0xe0, 0x34, 0xff, 0x73, 0xdd, 0x1e, 0x1b, 0x0c,
329    0xe0, 0x68, 0xf0, 0x8c, 0x7a, 0x4b, 0xcd, 0x1d, 0x3f, 0x38, 0x2d, 0xe8, 0x9b, 0x91, 0xa6, 0xfe,
330    0xa8, 0x8b, 0x45, 0x1c, 0xdf, 0xaf, 0x49, 0x34, 0x48, 0x17, 0x02, 0x28, 0xdb, 0xe0, 0x6e, 0x74,
331    0x34, 0xea, 0xac, 0x6b, 0x00, 0x45, 0x89, 0xa9, 0xb5, 0x63, 0xbd, 0x2f, 0xe0, 0x58, 0x2e, 0xd3,
332    0xc2, 0x74, 0xa2, 0x37, 0x37, 0x62, 0xf6, 0x76, 0x1b, 0x3f, 0xfb, 0x98, 0x64, 0x13, 0xd6, 0x8c,
333    0xa0, 0x0c, 0xbc, 0x54, 0x00, 0xe0, 0xf8, 0x63, 0x17, 0x22, 0x44, 0x36, 0xe0, 0x28, 0xa0, 0x7d,
334    0x50, 0x9e, 0x50, 0x94, 0xea, 0xd7, 0x62, 0xab, 0x6d, 0x7a, 0x19, 0xa4, 0xa2, 0x74, 0x79, 0x5d,
335    0x15, 0x85, 0x21, 0xfe, 0x9a, 0x35, 0x76, 0x40, 0x78, 0x01, 0xe3, 0x46, 0x2f, 0x6f, 0x2d, 0x0a,
336    0x1d, 0xac, 0x2e, 0x23, 0xec, 0xb8, 0x48, 0x74, 0xbc, 0xee, 0x29, 0x72, 0xb6, 0xe7, 0x52, 0x8c,
337    0xd4, 0x1a, 0x00, 0x34, 0x75, 0x1c, 0x4b, 0x83, 0x50, 0xbb, 0x57, 0x21, 0x9b, 0xd8, 0xb4, 0x75,
338    0xf3, 0x98, 0x8a, 0x9b, 0x45, 0xa8, 0x61, 0x50, 0x10, 0xb4, 0xec, 0x91, 0x2e, 0xe7, 0xf2, 0xb8,
339    0xb9, 0x62, 0x70, 0xc2, 0x93, 0xe7, 0xd9, 0xf1, 0x02, 0x27, 0xd7, 0xec, 0xde, 0x5b, 0x42, 0xa1,
340    0x26, 0x37, 0x41, 0x32, 0x65, 0x11, 0x63, 0x38, 0xbb, 0x6f, 0x23, 0x7a, 0xa0, 0xb7, 0x24, 0xeb,
341    0xa8, 0x38, 0x8b, 0xa7, 0x73, 0xe2, 0xc8, 0x30, 0x56, 0x73, 0x6f, 0x17, 0x6e, 0x1a, 0xe5, 0x32,
342    0xff, 0xd6, 0xa2, 0x08, 0x7b, 0x6a, 0x23, 0x33, 0x9f, 0x10, 0x05, 0x71, 0xdd, 0x02, 0x03, 0x01,
343    0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
344    0x14, 0xd2, 0xa5, 0x3b, 0xf2, 0x5d, 0xfd, 0x1f, 0x25, 0xda, 0xfb, 0x06, 0xfb, 0x59, 0x99, 0xc4,
345    0xac, 0xc4, 0x0b, 0xac, 0x64, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
346    0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
347    0x16, 0x80, 0x14, 0xd2, 0xa5, 0x3b, 0xf2, 0x5d, 0xfd, 0x1f, 0x25, 0xda, 0xfb, 0x06, 0xfb, 0x59,
348    0x99, 0xc4, 0xac, 0xc4, 0x0b, 0xac, 0x64, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
349    0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
350    0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x71, 0x10, 0x3c, 0x89, 0xd5,
351    0xc0, 0x00, 0xdc, 0x36, 0x1d, 0x93, 0xaa, 0xab, 0x4a, 0xb6, 0xfa, 0xa8, 0x5b, 0x89, 0x1c, 0xb3,
352    0x4a, 0x04, 0x2e, 0xb3, 0x25, 0x0f, 0x12, 0x07, 0x29, 0x70, 0x3d, 0x34, 0xd1, 0xdd, 0x7e, 0x30,
353    0xfd, 0xf5, 0xfa, 0x94, 0xf4, 0xcb, 0xdb, 0xac, 0x1b, 0xed, 0xe5, 0x11, 0x4a, 0xc8, 0xab, 0x26,
354    0xe2, 0x41, 0xcb, 0xa5, 0x74, 0x4b, 0xe1, 0xd2, 0xf3, 0x83, 0x1c, 0x7a, 0xcb, 0x29, 0xd9, 0xd2,
355    0xa6, 0x9d, 0x08, 0x95, 0x73, 0x63, 0xe2, 0x9c, 0xeb, 0xa5, 0x82, 0x8b, 0x6c, 0xf4, 0x64, 0x98,
356    0x03, 0x53, 0x91, 0x35, 0x04, 0x89, 0x25, 0xa0, 0x1f, 0xdc, 0x42, 0xf7, 0x59, 0x44, 0x63, 0x75,
357    0xe6, 0x49, 0x10, 0x66, 0x0f, 0x08, 0x07, 0x39, 0xc4, 0x3e, 0x1f, 0xba, 0x30, 0x42, 0xf8, 0x7a,
358    0xc8, 0xbe, 0x6f, 0xdb, 0xec, 0x16, 0xb2, 0x76, 0x84, 0x2c, 0x6e, 0x20, 0xd1, 0xbd, 0xd5, 0x90,
359    0x22, 0x0a, 0x90, 0x5c, 0x70, 0x47, 0xc9, 0x2d, 0xe3, 0x77, 0x74, 0xfd, 0xbb, 0x85, 0x1a, 0xd8,
360    0x5c, 0x38, 0x94, 0x4c, 0x83, 0x28, 0x23, 0xa5, 0x4f, 0x55, 0x5f, 0xe3, 0x42, 0x80, 0x10, 0xd4,
361    0xa5, 0x8d, 0xcf, 0x8b, 0x53, 0x69, 0x6d, 0xc5, 0x37, 0xd2, 0xfa, 0xbb, 0xc0, 0x5a, 0xab, 0x6f,
362    0x71, 0x37, 0x92, 0xd4, 0x90, 0xef, 0x5d, 0xf1, 0xc3, 0xb8, 0x64, 0x08, 0xd3, 0xba, 0x36, 0x69,
363    0x2b, 0x00, 0xed, 0xad, 0x36, 0x21, 0x38, 0xdf, 0x4a, 0xc6, 0x44, 0xc4, 0x6b, 0xd8, 0xb0, 0x7f,
364    0x67, 0x05, 0xaa, 0x6f, 0x9e, 0x8a, 0xf1, 0x81, 0x95, 0x99, 0xb9, 0x56, 0xf4, 0x73, 0xa7, 0xb4,
365    0x19, 0xb9, 0x4b, 0xb8, 0x1d, 0x10, 0xa5, 0x88, 0x7c, 0x39, 0xa3, 0x85, 0xe7, 0xba, 0x65, 0x86,
366    0xca, 0xf7, 0x0e, 0xe0, 0x0d, 0x73, 0x3f, 0xea, 0x98, 0x88, 0x58, 0x73, 0xfa, 0x68, 0x5b, 0xaa,
367    0x8c, 0xfd, 0x3e, 0x22, 0x3e, 0x92, 0xc7, 0xe2, 0x77, 0x14, 0x81, 0xe6, 0xd9, 0xdc, 0xc1, 0xe9,
368    0xc0, 0x06, 0x57, 0xb4, 0xca, 0xb6, 0x14, 0x15, 0x16, 0x80, 0x7e, 0xc5, 0x11, 0xa4, 0x05, 0x66,
369    0xad, 0x1d, 0xa3, 0xb6, 0xab, 0x2a, 0xbe, 0xd0, 0x52, 0x4e, 0x9e, 0x84, 0x61, 0x6b, 0xf4, 0x34,
370    0x23, 0x94, 0x24, 0xc6, 0xc8, 0xb0, 0x94, 0x22, 0x4c, 0x3b, 0xac, 0x85, 0xe3, 0xd4, 0xf7, 0x38,
371    0xe5, 0x9a, 0x76, 0xb3, 0x1b, 0xf0, 0xbc, 0x78, 0xc6, 0x6f, 0x11, 0xb3, 0x1a, 0x5c, 0x4f, 0x07,
372    0x52, 0x06, 0x92, 0x7a, 0x25, 0x86, 0x91, 0x71, 0x8a, 0xf4, 0x03, 0xce, 0x19, 0x0d, 0xfc, 0xde,
373    0x8f, 0xc9, 0x4e, 0x84, 0xf1, 0x17, 0x18, 0x6f, 0x37, 0x56, 0xb9, 0x76, 0x7e, 0x8f, 0xca, 0xde,
374    0xd4, 0x1b, 0x2d, 0x8d, 0xcf, 0x12, 0x9f, 0xf9, 0xb9, 0x8b, 0x82, 0x8f, 0x4d, 0xb7, 0x63, 0x26,
375    0x8d, 0xda, 0x35, 0x94, 0x18, 0xf9, 0x55, 0xca, 0x39, 0x09, 0xe9, 0x62, 0xe1, 0x00, 0xd8, 0x67,
376    0xed, 0x5e, 0x84, 0xc2, 0xe5, 0x8e, 0x46, 0x57, 0xa4, 0xa7, 0x17, 0x70, 0xcf, 0x6d, 0xdf, 0x43,
377    0x64, 0x2b, 0x36, 0xe6, 0xf3, 0xc1, 0x4c, 0x7a, 0x7e, 0x9e, 0x47, 0xc4, 0x14, 0x82, 0xbe, 0x94,
378    0x73, 0x54, 0xd0, 0x2c, 0xc2, 0x31, 0xc6, 0xd5, 0xc3, 0xd7, 0xa9, 0xef, 0x11, 0x24, 0x2f, 0xd0,
379    0x5b, 0xb8, 0x6a, 0x8e, 0x3c, 0xb7, 0x4b, 0x00, 0x9b, 0xc1, 0xca, 0x00, 0x6f, 0xd4, 0x73, 0x93,
380    0x2e, 0x39, 0x37, 0x2a, 0x73, 0x44, 0x9b, 0x1b, 0x05, 0x1a, 0x7c, 0x2f, 0xc9, 0x2b, 0x37, 0xf3,
381    0xcd, 0x8c, 0x4e, 0xc2, 0x7a, 0x6e, 0xd9, 0xd4, 0xf1, 0x8d, 0x6d, 0x07, 0x4b, 0xb5, 0x09, 0xb9,
382    0x48, 0x55, 0xac, 0xc6, 0x7e, 0xbc, 0xc6, 0x76, 0xeb, 0x5f, 0x0f               
383
384};
385
386static NSDictionary* VerifyMessage(CFDataRef message, SecPolicyRef policy,  CFDataRef cert_data)
387{
388	NSDictionary* result = nil;
389    
390	SecTrustRef trustRef = NULL;
391	CFDataRef payload = NULL;
392	CFArrayRef anchors = NULL;
393	OSStatus status = noErr;
394    SecCertificateRef aCertRef = NULL;
395	SecTrustResultType trust_result = kSecTrustResultRecoverableTrustFailure;
396	
397	if (NULL == message || NULL == policy || NULL == cert_data)
398	{
399		goto out;
400	}
401    
402	status = SecCMSVerifyCopyDataAndAttributes(message, NULL, policy, &trustRef, &payload, NULL);
403	if (noErr != status || NULL == trustRef || NULL == payload)
404	{
405		goto out;
406	}
407            
408    aCertRef = SecCertificateCreateWithData(NULL, cert_data);
409    if (NULL == aCertRef)
410    {
411        goto out;
412    }
413	
414	anchors = CFArrayCreate(kCFAllocatorDefault, (const void **)&aCertRef, 1, &kCFTypeArrayCallBacks);
415	if (NULL == anchors)
416	{
417		goto out;
418	}
419    	
420	status = SecTrustSetAnchorCertificates(trustRef,  anchors);
421	if (noErr != status)
422	{
423		goto out;
424	}
425	
426	status = SecTrustEvaluate(trustRef, &trust_result);
427        
428	if (noErr != status)
429	{
430		goto out;
431	}    
432	
433	if (trust_result == kSecTrustResultUnspecified)
434	{
435		// Life is good and we got back the expected result.
436       		
437		NSData* property_list_data = CFBridgingRelease(payload);
438		
439		NSPropertyListFormat format;
440		NSError* error = nil;
441		result = [NSPropertyListSerialization propertyListWithData:property_list_data options:0 format:&format error:&error];
442		if (nil != error)
443		{
444			result = nil;
445		}
446	}
447	
448out:
449    CFReleaseSafe(aCertRef)
450	CFReleaseSafe(anchors);
451	return result;
452}
453
454/* ==========================================================================
455	Private Methods for the OTAServiceApp class
456   ========================================================================== */
457@interface OTAServiceApp (PrivateMethods)
458- (void)processAssets:(NSArray*)assets;
459- (BOOL)checkAssetVersions:(NSString *)assetDir;
460- (BOOL)validateAsset:(NSString *)assetDir;
461- (BOOL)validateDirectory:(NSString *)assetDir withFiles:(NSArray *)file_names;
462- (NSDictionary *)decodeManifest:(NSData *)manifest_file_data;
463- (BOOL)checkFileHash:(NSString *)file_path hash:(NSData *)hash;
464- (BOOL)installAssetFiles:(NSString *)assetDir;
465- (NSString*)getCurrentAssetDirectory;
466
467@end
468
469@implementation OTAServiceApp
470
471@synthesize file_list = _file_list;
472@synthesize manifest_file_name = _manifest_file_name;
473@synthesize asset_version_file_name = _asset_version_file_name;
474@synthesize current_asset_version = _current_asset_version;
475@synthesize next_asset_version = _next_asset_version;
476@synthesize fileManager = _fileManager;
477@synthesize current_asset_directory = _current_asset_directory;
478@synthesize assets_directory = _assets_directory;
479
480/* --------------------------------------------------------------------------
481	OTAServiceApp  init:withArguments:
482	
483	Initialize a new instance of the OTAServiceApp class
484   -------------------------------------------------------------------------- */
485- (id)init:(int)argc withArguments:(const char**)argv
486{
487	if ((self = [super init]))
488	{
489		_fileManager = [NSFileManager defaultManager];
490		
491		_manifest_file_name = (NSString *)kManifestFileName;
492		_asset_version_file_name = (NSString *)kAssetVersionFileName;
493		_file_list = [NSArray arrayWithObjects:kBlockKeyFileName, kGrayListedKeysFileName, 
494								kEVRootsFileName, kCertsIndexFileName, kCertsTableFileName,
495								kManifestFileName, kAssetVersionFileName, kAppleESCertificatesName, nil];	
496								
497		_current_asset_version = nil;
498		_next_asset_version = nil;
499		_assets_directory = nil;	
500		_current_asset_directory = [self getCurrentAssetDirectory];
501		
502		/* Default interval is one hour */
503		_asset_query_retry_interval = 60.0 * 60;
504		_verbose = false;
505		
506		int ch;
507		while ((ch = getopt(argc, (char * const *)argv, "d:v")) != -1 )
508		{
509			switch (ch)
510			{
511				case 'd':
512				{
513					char *endptr = NULL;
514					errno = 0;
515					CFTimeInterval interval = strtod(optarg, &endptr);
516					if ((interval == 0 && endptr == optarg) || errno == ERANGE) {
517						syslog(LOG_ERR, "invalid argument '%s', ignoring", optarg);
518					} else {
519						syslog(LOG_NOTICE, "Setting query retry interval to %f seconds", interval);
520						_asset_query_retry_interval = (CFTimeInterval)interval;
521					}
522				}
523					break;
524				case 'v':
525					syslog(LOG_NOTICE, "Enabling verbose logging");
526					_verbose = true;
527					break;
528				default:
529					break;
530			}
531		}
532        
533        struct stat info;
534#if NEW_LOCATION
535        if (stat([kBaseAssetDirectoryPath UTF8String], &info))
536		{
537			OTAPKI_LOG("OTAServiceApp.init:withArguments: stat of %s failed\n", [kBaseAssetDirectoryPath UTF8String]);
538			
539			if (mkdir([kBaseAssetDirectoryPath UTF8String], kAssetDirectoryPermission))
540			{
541				OTAPKI_LOG("OTAServiceApp.init:withArguments: mkdir of %s failed\n", [kBaseAssetDirectoryPath UTF8String]);
542			}
543			else
544			{
545				if (stat([kBaseAssetDirectoryPath UTF8String], &info))
546				{
547					OTAPKI_LOG("OTAServiceApp.init:withArguments: second stat of %s failed\n", [kBaseAssetDirectoryPath UTF8String]);
548				}
549			}
550		}
551#else
552		stat([kBaseAssetDirectoryPath UTF8String], &info);
553		
554        _uid = info.st_uid;
555        _gid = info.st_gid;
556#endif
557        
558	}
559   
560    return self;
561}
562
563#if !TARGET_IPHONE_SIMULATOR
564
565- (void)registerBackgroundTaskAgentJobWithDelay:(CFTimeInterval)delay
566{
567	/*
568	 * ELEs are very important, so allow asset queries on any network type and 
569	 * construct the job so that it will fire as soon as possible, unless we are
570	 * scheduling a retry after a failure.
571	 */
572	xpc_object_t job = xpc_dictionary_create(NULL, NULL, 0);
573	if (delay != 0)
574	{
575		xpc_dictionary_set_double(job, kBackgroundTaskAgentJobWindowStartTime, CFAbsoluteTimeGetCurrent() + delay);
576	}
577	xpc_dictionary_set_double(job, kBackgroundTaskAgentJobWindowEndTime, CFAbsoluteTimeGetCurrent() + BACKGROUND_TASK_AGENT_JOB_WINDOW_MAX_TIME_FROM_NOW_SEC);
578	xpc_dictionary_set_bool(job, kBackgroundTaskAgentNetworkRequired, true);
579	xpc_dictionary_set_bool(job, kBackgroundTaskAgentCellularAllowed, true);
580	xpc_dictionary_set_bool(job, kBackgroundTaskAgentAllowedDuringRoaming, true);
581	xpc_dictionary_set_bool(job, kBackgroundTaskAgentPowerOptLevel, kBackgroundTaskAgentPowerDontCare);
582	
583	if (_verbose)
584	{
585		char *desc = xpc_copy_description(job);
586		syslog(LOG_NOTICE, "Adding BTA job %s", desc);
587		free(desc);
588	}
589#pragma GCC diagnostic push
590#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
591	BackgroundTaskAgentAddJob(kOTAPKIAssetToolActivity, job);
592#pragma GCC diagnostic pop
593}
594
595#endif
596
597/* --------------------------------------------------------------------------
598	OTAServiceApp checkInWithActivity
599	
600	Check in with the XPC activity configured in OTAPKIAssetTool's launchd
601	plist.  This activity will launch OTAPKIAssetTool every three days (with
602	some leeway decided by the system).  At that time, we schedule a
603	BackgroundTaskAgent job to be notified immediately when the network is
604	available so we can perform an asset query.
605   -------------------------------------------------------------------------- */
606- (void)checkInWithActivity
607{
608#if !TARGET_IPHONE_SIMULATOR
609#pragma GCC diagnostic push
610#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
611	BackgroundTaskAgentInit("com.apple.OTAPKIAssetTool", dispatch_get_main_queue(), ^(const char *job_name, xpc_object_t job)
612	{
613		/*
614		 * We're doing real work at this point, so open a transaction so
615		 * that the system (hopefully) won't kill us while we're busy
616		 */
617		xpc_transaction_begin();
618		
619		if (_verbose)
620		{
621			syslog(LOG_NOTICE, "BackgroundTaskAgent job %s fired", job_name);
622		}
623		
624		int64_t job_status = xpc_dictionary_get_int64(job, kBackgroundTaskAgentJobStatus);
625		if (job_status == kBackgroundTaskAgentJobRequestError)
626		{
627			syslog(LOG_ERR, "Failed to create BTA job -- malformed job?");
628		}
629		else if (job_status == kBackgroundTaskAgentJobSatisfied)
630		{
631			if (_verbose)
632			{
633				syslog(LOG_NOTICE, "BTA job %s is satisfied -- performing asset query", job_name);
634			}
635			bool shouldReschedule = false;
636			if ([self run:&shouldReschedule] || !shouldReschedule)
637			{
638				if (_verbose)
639				{
640					syslog(LOG_NOTICE, "Unscheduling BTA job");
641				}
642				BackgroundTaskAgentRemoveJob(kOTAPKIAssetToolActivity);
643			}
644			else
645			{
646				syslog(LOG_NOTICE, "Asset query failed due to network error. Re-scheduling BTA job for another attempt in %f seconds.", _asset_query_retry_interval);
647				[self registerBackgroundTaskAgentJobWithDelay:_asset_query_retry_interval];
648			}
649		}
650		else if (job_status == kBackgroundTaskAgentJobUnsatisfied)
651		{
652			/*
653			 * We will receive this if the job expires before we get to do our
654			 * work.  We still want to check for new assets as soon as possible,
655			 * so reschedule the job.
656			 */
657			if (xpc_dictionary_get_bool(job, kBackgroundTaskAgentJobExpired))
658			{
659				[self registerBackgroundTaskAgentJobWithDelay:0];
660			}
661		}
662		
663		xpc_transaction_end();
664	});
665#pragma GCC diagnostic pop
666#endif
667	
668	xpc_activity_register(kOTAPKIAssetToolActivity, XPC_ACTIVITY_CHECK_IN, ^(xpc_activity_t activity)
669	{
670		xpc_activity_state_t state = xpc_activity_get_state(activity);
671		
672		if (_verbose)
673		{
674			xpc_object_t criteria = xpc_activity_copy_criteria(activity);
675			
676			if (criteria != NULL)
677			{
678				char *desc = xpc_copy_description(criteria);
679				syslog(LOG_NOTICE, "Criteria for XPC activity %s: %s", kOTAPKIAssetToolActivity, desc);
680				free(desc);
681			}
682			else
683			{
684				syslog(LOG_NOTICE, "No critera for XPC activity %s", kOTAPKIAssetToolActivity);
685			}
686		}
687		
688		if (state == XPC_ACTIVITY_STATE_CHECK_IN)
689		{
690			/*
691			 * The activity is already configured in the launchd plist, so there
692			 * is nothing to do here
693			 */
694			if (_verbose)
695			{
696				syslog(LOG_NOTICE, "Activity %s in check in state", kOTAPKIAssetToolActivity);
697			}
698		}
699		else if (state == XPC_ACTIVITY_STATE_RUN)
700		{
701#if !TARGET_IPHONE_SIMULATOR
702#pragma GCC diagnostic push
703#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
704			xpc_object_t job = BackgroundTaskAgentCopyJob(kOTAPKIAssetToolActivity);
705#pragma GCC diagnostic pop
706			if (job == NULL)
707			{
708				syslog(LOG_NOTICE, "Activity %s in run state. Scheduling BTA job for earliest network availability.", kOTAPKIAssetToolActivity);
709				[self registerBackgroundTaskAgentJobWithDelay:0];
710			}
711			else if (_verbose)
712			{
713				syslog(LOG_NOTICE, "Already have a BTA job registered. Ignoring activity.");
714			}
715#else
716			/*
717			 * BackgroundTaskAgent doesn't exist on the iOS simulator, so we
718			 * just directly try to find and download new assets.
719			 */
720			xpc_transaction_begin();
721			bool shouldReschedule = false;
722			if (![self run:&shouldReschedule]) {
723				syslog(LOG_NOTICE, "Asset query failed%s.", shouldReschedule ? " due to network issue" : "");
724			}
725			xpc_transaction_end();
726#endif
727		}
728	});
729}
730
731/* --------------------------------------------------------------------------
732	OTAServiceApp  run
733	
734	Run this program and leave.  This program will currently run every 3 days,
735	with some leeway based on network availability.  That will provide the
736	longest time from publisihing a change in the PKI trust setting asset and
737	having that asset be consumed by a device.
738	
739	The program simnply ask the mobile asset daemon if there are any assets
740	to be processed with the PKITrustDataAssetType.  If not this program 
741	will just complete and will be re-run in 3 days.  If there is an asset to 
742	process then the asset will be process and then the program will complete.
743 
744	Returns false if the operation failed.  On return, shouldReschedule is set
745	to true if the operation failed due to a network error and the caller
746	should reschedule this operation at a more opportune time.
747   -------------------------------------------------------------------------- */
748- (bool)run:(bool *)shouldReschedule
749{
750	@autoreleasepool
751	{
752		if (shouldReschedule != NULL) {
753			*shouldReschedule = false;
754		}
755		
756		syslog(LOG_NOTICE, "OTAPKIAssetTool running");
757		if (![[MCProfileConnection sharedConnection] isOTAPKIUpdatesAllowed])
758	    {
759            syslog(LOG_NOTICE, "OTAPKIAssetTool: OTAPKI updates are not allowed.");
760	        return false;
761	    }
762	
763		ASAssetQuery *assetQuery = [[ASAssetQuery alloc] initWithAssetType:(NSString *)kPKITrustDataAssetType];
764		if (assetQuery == nil) 
765		{
766            syslog(LOG_NOTICE, "OTAPKIAssetTool: Could not create the asset query.");
767			return false;
768		}
769		
770		// Get the asset synchronously
771		NSError *error = nil;
772		NSArray *foundAssets = [assetQuery runQueryAndReturnError:&error];
773		if (nil != foundAssets) 
774		{
775			[self processAssets:foundAssets];
776		}
777        else
778        {
779			syslog(LOG_NOTICE, "OTAPKIAssetTool: No assets returned from query: %s", [[error description] UTF8String]);
780			
781			NSArray *networkErrorCodes = @[ @(ASErrorNetwork), @(ASErrorNetworkNoConnection), @(ASErrorNetworkTimedOut), @(ASErrorNetworkUnexpectedResponse) ];
782			if ([[error domain] isEqualToString:ASErrorDomain] && [networkErrorCodes containsObject:@([error code])])
783			{
784				syslog(LOG_NOTICE, "OTAPKIAssetTool: Query failed due to network error.");
785				if (shouldReschedule != NULL) {
786					*shouldReschedule = true;
787				}
788			}
789			return false;
790        }
791		
792		return true;
793	}
794}
795
796/* --------------------------------------------------------------------------
797	OTAServiceApp  processAssets:
798	
799	If when run is called asset(s) are found they will be processed here.
800   -------------------------------------------------------------------------- */  
801- (void)processAssets:(NSArray*)assets
802{
803	if (nil == assets)
804	{
805		return;
806	}
807        
808	NSError* error = nil;
809    ASAsset* asset = nil;
810    int asset_version = 0;
811
812	for (asset in assets)
813	{
814        NSDictionary* asset_attributes = asset.attributes;
815        
816        NSNumber* contentVersion = [asset_attributes objectForKey:@"ContentVersion"];
817		OTAPKI_LOG("In processAssets: about to check the ContentVersion\n");
818        if (nil != contentVersion)
819        {
820            asset_version = [contentVersion intValue];
821            int current_asset_version_number = (nil != _current_asset_version) ? [_current_asset_version intValue] : 0;
822            
823            if (asset_version <= current_asset_version_number)
824            {
825                syslog(LOG_NOTICE, "OTAPKIAssetTool: content version %d is too small.  Current asset version id %d",
826                       asset_version, current_asset_version_number);
827                
828				OTAPKI_LOG("In processAssets: content version is too small: current asset version is %d\nContent version is %d\n",
829					current_asset_version_number, asset_version);                
830				asset = nil;
831                continue;
832            }
833        }
834        
835        if (nil == asset)
836		{
837            syslog(LOG_NOTICE, "OTAPKIAssetTool: no suitable asset found");
838			return;
839		}
840        
841
842		// Check to see if the asset needs to be downloaded
843		if (asset.state == ASAssetStateNotPresent)
844		{
845			__block dispatch_semaphore_t sem = dispatch_semaphore_create(0);
846
847			[asset setProgressHandler:^(NSDictionary *state, NSError *anError)
848			{
849				if (error != nil) 
850				{
851					// An error occured.  Signal the semaphore to bail
852					dispatch_semaphore_signal(sem);
853				}
854				else if ([[state objectForKey:@"Operation"] isEqualToString:(NSString *) @"OperationCompleted"]) 
855				{
856					// The download is complete.  Signal the semaphore
857					dispatch_semaphore_signal(sem);
858				}
859			}];
860			
861            NSNumber* yesValue = [NSNumber numberWithBool:YES];
862            const id keys[] = {ASDownloadOptionAllow3G, ASDownloadOptionAllow4G, ASDownloadOptionPriority, ASDownloadOptionAllowBatteryPower};
863            const id values[] = {yesValue, yesValue, ASDownloadPriorityHigh, yesValue};
864            
865            NSDictionary* options = [NSDictionary dictionaryWithObjects:values forKeys:keys count:(sizeof (keys) / sizeof(keys[0]))];
866            
867  			[asset beginDownloadWithOptions:options];
868			dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
869		}
870		
871		// Check to see if the asset is now available for processing
872		if ([asset state] == ASAssetStateInstalled)
873		{
874			// Get the asset data directory
875			NSString* assetDir = [[[asset localURL] URLByAppendingPathComponent:@"PKITrustData"] path];
876			if (nil != assetDir)
877			{
878				// validate the asset. 
879				OTAPKI_LOG("In processAssets: about to validateAsset\n");
880				if ([self validateAsset:assetDir])
881				{
882					OTAPKI_LOG("In processAssets: asset validated installing\n");
883					// The asset is valid so install the files
884					[self installAssetFiles:assetDir];
885					
886					// Signal securityd to idle-exit at it's next opportunity
887					OTAPKI_LOG("In processAssets: notifying securityd\n");
888					int didUpdate = 0;
889					(void)SecTrustOTAPKIGetUpdatedAsset(&didUpdate);
890                    syslog(LOG_NOTICE, "OTAPKIAssetTool: installed new asset %d", asset_version);
891				}
892                else
893                {
894                    syslog(LOG_NOTICE, "OTAPKIAssetTool: Asset %d did not validate", asset_version);
895                }
896                
897				// regaurdless if the asset is valid.  Now that it is 
898				// installed, it needs to be purged to ensure that 
899				// we can retrieve a new updated asset.
900                [asset purgeAndReturnError:&error];
901			}
902            else
903            {
904                syslog(LOG_NOTICE, "OTAPKIAssetTool: Asset directory %s not found", [assetDir UTF8String]);
905            }
906		}
907	}
908}
909
910/* --------------------------------------------------------------------------
911	OTAServiceApp  checkAssetVersions:
912	
913	If when run is called asset(s) are found they will be processed here.
914   -------------------------------------------------------------------------- */	
915- (BOOL)checkAssetVersions:(NSString *)assetDir
916{
917	BOOL result = NO;
918	
919	OTAPKI_LOG("Entering checkAssetVersions\n");
920        
921	if (nil == assetDir || nil == self.current_asset_version)
922	{
923		OTAPKI_LOG("checkAssetVersions: parameter error\n");
924		return result;
925	}
926	
927	// first get the new version number from the downloaded asset
928	NSString* next_asset_version_path = [assetDir stringByAppendingPathComponent:self.asset_version_file_name];
929	if (![self.fileManager fileExistsAtPath:next_asset_version_path])
930	{
931		// The asset is missing the AssertVersion.plist 
932		// This is an invalid asset
933		OTAPKI_LOG("checkAssetVersions: could not file asseet version file %s\n", [self.asset_version_file_name UTF8String]);
934		return result;
935	}
936	
937    NSError* error = nil;
938	NSInputStream* input_stream = [NSInputStream inputStreamWithFileAtPath:next_asset_version_path];
939	[input_stream open];
940	NSDictionary* asset_dict = [NSPropertyListSerialization propertyListWithStream:input_stream options:0 format:nil error:&error];
941	[input_stream close];
942	
943	if (nil != error)
944	{
945		OTAPKI_LOG("checkAssetVersions: error reading asset version file: %s\n", [[error localizedDescription] UTF8String]);
946		return result;
947	}
948	
949	_next_asset_version = [asset_dict objectForKey:kVersionNumberKey];
950	if (nil == _next_asset_version)
951	{
952		OTAPKI_LOG("asset_dict did not have a entry with a key of kVersionNumberKey\n");
953		return result;
954	}
955	
956	// Check the current asset version against the new asset version.  The new asset version MUST be larger than the
957	// current asset version
958	NSInteger current_asset_version_value = [self.current_asset_version integerValue];
959	NSInteger next_asset_version_value = [self.next_asset_version integerValue];
960
961	if (next_asset_version_value <= current_asset_version_value)
962	{
963		OTAPKI_LOG("heckAssetVersions: assert version too small.  current_asset_version_value = %d next_asset_version_value = %d\n",
964			current_asset_version_value, next_asset_version_value);
965		return result;
966	}
967	
968	return YES;
969}
970
971
972/* --------------------------------------------------------------------------
973	OTAServiceApp  validateAsset:
974	
975	Decode the manifest and verify the file hashes
976   -------------------------------------------------------------------------- */	
977- (BOOL)validateAsset:(NSString *)assetDir
978{
979	BOOL result = NO;
980	
981	OTAPKI_LOG("Enterning validateAsset\n");
982    	
983	if (![self validateDirectory:assetDir withFiles:self.file_list])
984	{
985		OTAPKI_LOG("validateAsset param\n");
986		return result;
987	}
988    	
989	NSString* manifest_file_path = [assetDir stringByAppendingPathComponent:self.manifest_file_name];
990	NSError* error = nil;
991	NSData* manifest_file_data = [NSData dataWithContentsOfFile:manifest_file_path options:0 error:&error];
992	if (nil != error)
993	{
994		OTAPKI_LOG("validateAsset: could not read manifest file. error = %s\n", [[error localizedDescription] UTF8String]);
995		return result;
996	}
997    	
998	NSDictionary* manifest_data = [self decodeManifest:manifest_file_data];
999	if (nil == manifest_data)
1000	{
1001		OTAPKI_LOG("validateAsset: decodeManifest failed!\n");
1002		return result;
1003	}
1004        
1005	NSString* full_file_path = nil;
1006	NSData* hash = nil;
1007	for (NSString* file_name in self.file_list)
1008	{
1009		if ([file_name isEqualToString:self.manifest_file_name])
1010		{
1011			continue;
1012		}
1013		
1014		hash = [manifest_data objectForKey:file_name];
1015		if (nil == hash)
1016		{
1017			OTAPKI_LOG("validateAsset: could not get hash for file %s\n", [file_name UTF8String]);
1018			return result;
1019		}
1020		
1021		full_file_path = [assetDir stringByAppendingPathComponent:file_name];
1022		if (![self checkFileHash:full_file_path hash:hash])
1023		{
1024			OTAPKI_LOG("validateAsset: hash for file %s does not match\n", [file_name UTF8String]);
1025			return result;
1026		}
1027	}
1028    	
1029	result = [self checkAssetVersions:assetDir];    
1030	return result;
1031}
1032
1033/* --------------------------------------------------------------------------
1034	OTAServiceApp  validateDirectory:withFiles:
1035	
1036	Ensure that a given directory has the files listed in the files_names 
1037    parameter
1038   -------------------------------------------------------------------------- */	
1039- (BOOL)validateDirectory:(NSString *)assetDir withFiles:(NSArray *)file_names
1040{
1041	BOOL result = NO;
1042	OTAPKI_LOG("Enterning validateDirectory\n");	
1043    
1044	if (nil == assetDir || nil == file_names)
1045	{
1046		OTAPKI_LOG("validateDirectory param error\n");
1047		return result;
1048	}
1049	NSError* error = nil;
1050	NSArray* dir_items = [self.fileManager contentsOfDirectoryAtPath:assetDir error:&error];
1051	if (nil != error)
1052	{
1053		OTAPKI_LOG("validateDirectory: Error calling contentsOfDirectoryAtPath: error = %s\n", [[error localizedDescription] UTF8String]);
1054		return result;
1055	}
1056	
1057	for (NSString* file_name in file_names)
1058	{
1059		if (![dir_items containsObject:file_name])
1060		{
1061			OTAPKI_LOG("validateDirectory: missing file %s\n", [file_name UTF8String]);
1062			return result;
1063		}
1064	}
1065     
1066	return YES;	
1067}
1068
1069/* --------------------------------------------------------------------------
1070	OTAServiceApp  decodeManifest:
1071	
1072	Ensure that the asset manifest blob has it CMS signature verified
1073   -------------------------------------------------------------------------- */
1074- (NSDictionary *)decodeManifest:(NSData *)manifest_file_data
1075{
1076	NSDictionary* result = nil;
1077	CFDataRef cert_data = NULL;
1078	CFDataRef message = NULL;
1079	SecPolicyRef policy = NULL;
1080	CFBooleanRef mgResult = NULL;
1081	
1082	OTAPKI_LOG("Enterning decodeManifest\n");
1083	
1084	if (nil == manifest_file_data)
1085	{
1086		OTAPKI_LOG("decodeManifest: parameter error\n");
1087		goto out;
1088	}
1089	
1090	message = CFBridgingRetain(manifest_file_data);
1091	
1092	policy = SecPolicyCreateOTAPKISigner();
1093	if (NULL == policy)
1094	{
1095		OTAPKI_LOG("decodeManifest: could not get the SecPolicyCreateOTAPKISigner policyRef\n");
1096		goto out;
1097	}
1098    	
1099	cert_data = CFDataCreate(kCFAllocatorDefault, kApplePKISettingsRootCACert, sizeof(kApplePKISettingsRootCACert));
1100	if (NULL == cert_data)
1101	{
1102		OTAPKI_LOG("decodeManifest: could not kApplePKISettingsRootCACert data\n");
1103		goto out;
1104	}
1105		
1106	result = VerifyMessage(message, policy, cert_data);
1107    
1108	if (NULL != result)
1109	{
1110		OTAPKI_LOG("decodeManifest: SecPolicyCreateOTAPKISigner success!\n");
1111		goto out;
1112	}
1113	
1114	OTAPKI_LOG("decodeManifest: SecPolicyCreateOTAPKISigner failed! Checking to see if this is an internal build\n");
1115    	
1116	// The first attempt did not work so check to see if this is running on an internal build.
1117	if (!MGIsQuestionValid(kMGQAppleInternalInstallCapability))
1118	{
1119		OTAPKI_LOG("decodeManifest: kMGQAppleInternalInstallCapability had an error\n");
1120		goto out;
1121	}	
1122    	
1123	mgResult = MGCopyAnswer(kMGQAppleInternalInstallCapability, NULL);
1124	
1125	if (NULL == mgResult || !CFEqual(mgResult, kCFBooleanTrue))
1126	{
1127		OTAPKI_LOG("decodeManifest: Not an internal build");
1128		goto out;
1129	}
1130	
1131	OTAPKI_LOG("decodeManifest: This is an internal build\n");
1132    	
1133	CFReleaseNull(policy);
1134	CFReleaseNull(cert_data);
1135	
1136	policy = SecPolicyCreateTestOTAPKISigner();
1137	if (NULL == policy)
1138	{
1139		OTAPKI_LOG("decodeManifest: could not SecPolicyCreateTestOTAPKISigner policyRef\n");
1140		goto out;
1141	}
1142    	
1143	cert_data = CFDataCreate(kCFAllocatorDefault, kAppleTestPKISettingsRootCACert, sizeof(kAppleTestPKISettingsRootCACert));
1144	if (NULL == cert_data)
1145	{
1146		OTAPKI_LOG("decodeManifest: could not kAppleTestPKISettingsRootCACert data\n");
1147		goto out;
1148	}
1149    	
1150	result = VerifyMessage(message, policy, cert_data);
1151    
1152out:
1153
1154    CFReleaseSafe(mgResult);
1155    CFReleaseSafe(message);
1156	CFReleaseSafe(policy);
1157	CFReleaseSafe(cert_data);
1158	return result;
1159}
1160
1161/* --------------------------------------------------------------------------
1162	OTAServiceApp  checkFileHash:hash:
1163	
1164	Ensure that the given asset file's hash is the same as in the manifest
1165   -------------------------------------------------------------------------- */
1166- (BOOL)checkFileHash:(NSString *)file_path hash:(NSData *)hash
1167{
1168	BOOL result = NO;
1169	if (nil == file_path || nil == hash)
1170	{
1171		return result;
1172	}
1173	
1174	NSError* error = nil;
1175	NSData* file_data = [NSData dataWithContentsOfFile:file_path options:0 error:&error];
1176	if (nil != error)
1177	{
1178		return result;
1179	}
1180    
1181	UInt8 buffer[CC_SHA256_DIGEST_LENGTH];
1182	memset(buffer, 0, CC_SHA256_DIGEST_LENGTH);
1183	CC_SHA256([file_data bytes], (CC_LONG)[file_data length], buffer);
1184	NSData* file_hash_data = [NSData dataWithBytesNoCopy:buffer length:CC_SHA256_DIGEST_LENGTH freeWhenDone:NO];
1185    
1186    result = [hash isEqualToData:file_hash_data];
1187       
1188	return result;
1189}
1190
1191/* --------------------------------------------------------------------------
1192	OTAServiceApp  installAssetFiles:
1193	
1194	Copy over the files into the /var/Keychains/Assets directory.  
1195   -------------------------------------------------------------------------- */
1196- (BOOL)installAssetFiles:(NSString *)assetDir
1197{
1198	BOOL result = NO;
1199	
1200	OTAPKI_LOG("Entering installAssetFiles\n");
1201    
1202	if (nil == assetDir)
1203	{
1204		OTAPKI_LOG("installAssetFiles: parameter error\n");
1205		return result;
1206	}
1207	
1208	if (nil == self.assets_directory)
1209	{
1210		OTAPKI_LOG("installAssetFiles: no assets directory\n");
1211		return result;
1212	}
1213	
1214	// Create a temp directory to hold the new asset files.
1215	NSString* tempDir = [self.assets_directory stringByAppendingPathComponent:@"TempAssetDir"];
1216	NSError* error = nil;
1217    
1218#if NEW_LOCATION
1219	id values[] = {[NSNumber numberWithUnsignedLong: kAssetDirectoryPermission]};
1220    id keys[] = {NSFilePosixPermissions};
1221    
1222	NSDictionary* attributes = [NSDictionary dictionaryWithObjects:values forKeys:keys count:1];
1223#else
1224    struct passwd *user_info = getpwnam([kAssetDirectoryUser UTF8String]);
1225    struct group *group_info = getgrnam([kAssetDirectoryGroup UTF8String]);
1226    NSNumber* uid_num = [NSNumber numberWithUnsignedInt: user_info->pw_uid];
1227    NSNumber* gid_num = [NSNumber numberWithUnsignedInt: group_info->gr_gid];
1228    
1229    id values[] = {uid_num, gid_num, [NSNumber numberWithUnsignedLong: kAssetDirectoryPermission]};
1230    id keys[] = {NSFileOwnerAccountID, NSFileGroupOwnerAccountID, NSFilePosixPermissions};
1231    
1232    NSDictionary* attributes = [NSDictionary dictionaryWithObjects:values forKeys:keys count:3];
1233#endif
1234    
1235    
1236	if (![self.fileManager createDirectoryAtPath:tempDir withIntermediateDirectories:YES
1237                                attributes:attributes error:&error])
1238	{
1239		OTAPKI_LOG("installAssetFiles: could not create directory %s\n", [tempDir UTF8String]);
1240		return result;
1241	}
1242    
1243#ifndef NEW_LOCATION
1244    // Copy all of the asset files to the newly created directory
1245	for (NSString* file_name in self.file_list)
1246	{
1247		NSString* download_assert_path = [assetDir stringByAppendingPathComponent:file_name];
1248		NSString* asset_path = [tempDir stringByAppendingPathComponent:file_name];
1249		if ([self.fileManager copyItemAtPath:download_assert_path toPath:asset_path error:&error])
1250		{
1251             chown([asset_path UTF8String], self.uid, self.gid);
1252        }
1253        else
1254        {
1255            [self.fileManager removeItemAtPath:tempDir error:nil];
1256			return result;
1257        }
1258	}
1259#endif // !NEW_LOCATION
1260
1261	
1262	// Now that all of the files have been copied to the temp directory make a single call
1263	// to rename (move) the temp directory to be the correct version directory.  This rename
1264	// allow for reducing a race conditions between this asset code and securityd.  
1265	NSInteger new_version_value = [self.next_asset_version integerValue];
1266	NSString* new_version_dir_name = [NSString stringWithFormat:@"%@%ld", kVersionDirectoryNamePrefix, (long)new_version_value];
1267	NSString* new_version_dir_path = [self.assets_directory stringByAppendingPathComponent:new_version_dir_name];
1268	if (![self.fileManager moveItemAtPath:tempDir toPath:new_version_dir_path error:&error])
1269  	{
1270		OTAPKI_LOG("installAssetFiles: could not move path %s\n", [tempDir UTF8String]);
1271		[self.fileManager removeItemAtPath:tempDir error:nil];
1272		return result;
1273	}
1274    
1275	result = YES;
1276	return result;
1277}
1278
1279/* --------------------------------------------------------------------------
1280	OTAServiceApp  getCurrentAssetDirectory:
1281	
1282	Looks through the /var/Keychains/Assets directory to find latest asset
1283    version directory.  If no assets have been downloaded then nil is returned
1284    and the current asset version is set to 0
1285   -------------------------------------------------------------------------- */
1286- (NSString*)getCurrentAssetDirectory
1287{
1288	NSString* result = nil;
1289	BOOL isDir = NO;
1290	
1291	OTAPKI_LOG("In getCurrentAssetDirectory\n");
1292	OTAPKI_LOG("getCurrentAssetDirectory: checking to see if %s exists\n", [kBaseAssetDirectoryPath UTF8String]);
1293	
1294	// Check to see if the base directory is there
1295	if (![self.fileManager fileExistsAtPath:(NSString *)kBaseAssetDirectoryPath isDirectory:&isDir] || !isDir)
1296	{
1297		OTAPKI_LOG("getCurrentAssetDirectory:  %s does not exists\n", [kBaseAssetDirectoryPath UTF8String]);
1298		// This might be fatal
1299		return result;
1300	}
1301	
1302	NSError* error = nil;
1303	NSInteger version_number = 0;
1304	NSInteger current_version_number = 0;
1305	int aVerNum = 0;
1306	OSStatus err = noErr;
1307	
1308	_assets_directory = [kBaseAssetDirectoryPath stringByAppendingPathComponent:(NSString *)kAssetDirectoryName];
1309	
1310	OTAPKI_LOG("getCurrentAssetDirectory: %s does exists\n", [self.assets_directory  UTF8String]);
1311	
1312	if ([self.fileManager fileExistsAtPath:self.assets_directory isDirectory:&isDir] && isDir)
1313	{
1314		OTAPKI_LOG("getCurrentAssetDirectory: %s does exists\n", [self.assets_directory  UTF8String]);
1315		NSDirectoryEnumerator* dirEnum = [self.fileManager enumeratorAtPath:self.assets_directory];
1316		[dirEnum skipDescendents];
1317		
1318		for (NSString* file in dirEnum)
1319		{
1320			if ([file hasPrefix:(NSString *)kVersionDirectoryNamePrefix])
1321			{
1322				NSString* version_str = [file substringFromIndex:[kVersionDirectoryNamePrefix length]];
1323                NSInteger aVersion_number = [version_str integerValue];
1324                if (aVersion_number > version_number)
1325                {
1326                    version_number = aVersion_number;
1327                }
1328			}
1329		}		
1330	}
1331	else
1332	{ 
1333#if NEW_LOCATION 
1334 		id values[] = {[NSNumber numberWithUnsignedLong: kAssetDirectoryPermission]};
1335        id keys[] = {NSFilePosixPermissions};
1336        
1337        NSDictionary* attributes = [NSDictionary dictionaryWithObjects:values forKeys:keys count:1];
1338#else
1339     
1340        struct passwd *user_info = getpwnam([kAssetDirectoryUser UTF8String]);
1341        struct group *group_info = getgrnam([kAssetDirectoryGroup UTF8String]);     
1342        NSNumber* uid_num = [NSNumber numberWithUnsignedInt: user_info->pw_uid];
1343        NSNumber* gid_num = [NSNumber numberWithUnsignedInt: group_info->gr_gid];
1344
1345        id values[] = {uid_num, gid_num, [NSNumber numberWithUnsignedLong: kAssetDirectoryPermission]};
1346        id keys[] = {NSFileOwnerAccountID, NSFileGroupOwnerAccountID, NSFilePosixPermissions};
1347        NSDictionary* attributes = [NSDictionary dictionaryWithObjects:values forKeys:keys count:3];
1348#endif
1349		OTAPKI_LOG("getCurrentAssetDirectory: %s does NOT exists\n", [self.assets_directory  UTF8String]);		
1350		OTAPKI_LOG("getCurrentAssetDirectory: creating %s\n", [self.assets_directory  UTF8String]);
1351		
1352		if (![self.fileManager createDirectoryAtPath:self.assets_directory withIntermediateDirectories:YES
1353                    attributes:attributes error:&error])
1354		{
1355			OTAPKI_LOG("getCurrentAssetDirectory: failed to create %s\n", [self.assets_directory  UTF8String]);
1356			return result;
1357		}
1358        
1359	}
1360			
1361	err = SecTrustGetOTAPKIAssetVersionNumber(&aVerNum);
1362	if (errSecSuccess == err && aVerNum > 0)
1363	{
1364		current_version_number = aVerNum;
1365	}
1366	
1367	if (version_number < current_version_number)
1368	{
1369		OTAPKI_LOG("The largest OTA version number is smaller than the current version number.  This means the system has a newer asset\n");
1370		version_number = current_version_number;
1371	}
1372	else
1373	{
1374		OTAPKI_LOG("The largest OTA version number is equal to the current version number.  The OTA asset is newer than the system asset\n");
1375		NSString* version_dir_name = [NSString stringWithFormat:@"%@%ld", kVersionDirectoryNamePrefix, (long)version_number];
1376		result = [self.assets_directory stringByAppendingPathComponent:version_dir_name];
1377	}
1378	
1379	OTAPKI_LOG("getCurrentAssetDirectory: setting version number to %d\n", version_number);
1380	_current_asset_version = [NSNumber numberWithInteger:version_number];
1381	return result;
1382}
1383
1384@end
1385