//
// OTAServiceApp.m
// Security
//
//
#import "OTAServiceApp.h"
#import <TargetConditionals.h>
#import <Security/Security.h>
#import <Security/SecPolicyPriv.h>
#import <Security/SecTrustPriv.h>
#import <syslog.h>
#import <xpc/xpc.h>
#import <MobileAsset/MobileAsset.h>
#import <Security/Security.h>
#import <Security/SecCMS.h>
#import <Security/SecCmsMessage.h>
#import <Security/SecCmsDecoder.h>
#import <Security/SecCmsContentInfo.h>
#import <Security/SecCmsSignedData.h>
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonDigestSPI.h>
#import <CommonNumerics/CommonBaseXX.h>
#import <ManagedConfiguration/MCProfileConnection.h>
#import <MobileGestalt.h>
#if !TARGET_IPHONE_SIMULATOR
#import <BackgroundTaskAgent/BackgroundTaskAgent.h>
#endif
#import <sys/types.h>
#import <pwd.h>
#import <stdlib.h>
#import <unistd.h>
#import <stdio.h>
#import <grp.h>
#import <sys/stat.h>
#import <syslog.h>
#define CFReleaseSafe(CF) { CFTypeRef _cf = (CF); if (_cf) { CFRelease(_cf); } }
#define CFReleaseNull(CF) { CFTypeRef _cf = (CF); if (_cf) { (CF) = NULL; CFRelease(_cf); } }
//#define VERBOSE_LOGGING 1
#if VERBOSE_LOGGING
static void OTAPKI_LOG(const char* sz, ...)
{
va_list va;
va_start(va, sz);
FILE* fp = fopen("/tmp/OTAPKITool.log", "a");
if (NULL != fp)
{
vfprintf(fp, sz, va);
fclose(fp);
}
va_end(va);
}
#else
#define OTAPKI_LOG(sz, ...)
#endif
//#define NEW_LOCATION 1
/* ==========================================================================
The following are a set of string constants used by this program.
kBaseAssetDirectoryPath - This is the full path on the device that
will contain the Assets directory. This
directory was chosen because it is owned
by securityd
kkManifestFileName - The file name of the manifest file for the
OTA PKI trust asset
kAllowListFileName - The file name of the asset file that contains
hashes of the allowed leaf certificates whose
trust store root has been removed
kAssetVersionFileName - The file name of the plist file in the asset
that contains the version number of this
OTA PKI trust asset. It is a plist that is a
dictionary with a single key with a single
key value pair that has the version number
of the asset. This is used to ensure against
anti-replay.
kBlockKeyFileName - The file name of the asset file that contains
blocked keys. Any certificate with these keys
will be marked as not being trusted.
kGrayListedKeysFileName - The file name of the asset file that contains
gray listed keys. If a chain has any of these
keys, than the chain will still be approved but
an entry will be added to the details dictionary
noting that the key was gray listed
kEVRootsFileName - The file name of the asset file that contains
the list of EV OIDS and their corresponding
certificates. This file sets which certs will
be considered to be EV.
kCTLogsFileName - The file name of the asset file that contains
the list of Certificate Transparency logs and
their public keys.
kCertsIndexFileName - The file name of the asset file that contains
a hash table of offsets into the cert table
file. This is used to look up anchor certs.
kCertsTableFileName - The file name of the asset file that contains
all of the anchor certificates. The
kCertsIndexFileName file is used to find the
correct offset in this file to retrieve a
specific anchor certificate.
kVersionNumberKey - The dictionary key for the kAssetVersionFileName
file to get the version number
kVersionDirectoryNamePrefix -
The directory name prefix for all of the
asset directorys
kPKITrustDataAssetType - The asset identifier of the OTA PKI asset
========================================================================== */
#if NEW_LOCATION
static const NSString* kBaseAssetDirectoryPath = @"/var/OTAPKI";
#else
static const NSString* kBaseAssetDirectoryPath = @"/var/Keychains";
#endif
static const NSString* kManifestFileName = @"manifest.data";
static const NSString* kAllowListFileName = @"Allowed.plist";
static const NSString* kAssetVersionFileName = @"AssetVersion.plist";
static const NSString* kAppleESCertificatesName = @"AppleESCertificates.plist";
static const NSString* kBlockKeyFileName = @"Blocked.plist";
static const NSString* kGrayListedKeysFileName = @"GrayListedKeys.plist";
static const NSString* kEVRootsFileName = @"EVRoots.plist";
static const NSString* kCTLogsFileName = @"TrustedCTLogs.plist";
static const NSString* kCertsIndexFileName = @"certsIndex.data";
static const NSString* kCertsTableFileName = @"certsTable.data";
static const NSString* kVersionNumberKey = @"VersionNumber";
static const NSString* kAssetDirectoryName = @"Assets";
static const NSString* kAssetDirectoryUser = @"_securityd";
static const NSString* kAssetDirectoryGroup = @"wheel";
#if NEW_LOCATION
static const unsigned long kAssetDirectoryPermission = S_IRWXU | S_IRWXG | S_IRWXO;
#else
static const unsigned long kAssetDirectoryPermission = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
#endif
static const NSString* kVersionDirectoryNamePrefix = @"Version_";
static const NSString* kPKITrustDataAssetType =@"com.apple.MobileAsset.PKITrustServices.PKITrustData";
const char *kOTAPKIAssetToolActivity = "com.apple.OTAPKIAssetTool.asset-check";
const char *kOTAPKIAssetToolBTAJob = "com.apple.BTA.OTAPKIAssetTool.asset-check";
static const UInt8 kApplePKISettingsRootCACert[] = {
0x30, 0x82, 0x07, 0xca, 0x30, 0x82, 0x05, 0xb2, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x4e,
0xa1, 0x31, 0xe7, 0xca, 0x50, 0xb8, 0x97, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00, 0x30, 0x81, 0x84, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55,
0x04, 0x03, 0x0c, 0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65,
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
0x69, 0x74, 0x79, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70,
0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x13, 0x30, 0x11, 0x06,
0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e,
0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x30, 0x1e, 0x17,
0x0d, 0x31, 0x33, 0x30, 0x36, 0x32, 0x34, 0x32, 0x33, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x17, 0x0d,
0x34, 0x33, 0x30, 0x36, 0x31, 0x37, 0x32, 0x33, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x30, 0x81, 0x84,
0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65,
0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f,
0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03,
0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
0x74, 0x79, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70,
0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
0x13, 0x02, 0x55, 0x53, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a,
0x02, 0x82, 0x02, 0x01, 0x00, 0xce, 0x15, 0xf7, 0x6f, 0xd8, 0x42, 0x0c, 0x6f, 0x45, 0xb4, 0x04,
0x59, 0x24, 0xcb, 0x70, 0x88, 0x84, 0x77, 0xa1, 0x91, 0x54, 0xf4, 0x87, 0x61, 0xb3, 0xd3, 0xfc,
0xbe, 0xb6, 0x05, 0x3c, 0xb9, 0xb7, 0x7d, 0x7c, 0xbc, 0x0b, 0xe8, 0x87, 0x07, 0xcf, 0x20, 0xbe,
0xaa, 0xeb, 0x24, 0xc5, 0xe4, 0x5c, 0xcd, 0xcb, 0x89, 0x9f, 0x7a, 0xea, 0xb4, 0x5d, 0x3b, 0x29,
0x6c, 0xba, 0x4d, 0x15, 0xfb, 0x59, 0xd0, 0x5a, 0xea, 0x41, 0x4e, 0x0d, 0x1d, 0xf7, 0x66, 0x77,
0xa2, 0x96, 0x56, 0xed, 0xd1, 0x16, 0x7b, 0xea, 0xf5, 0x60, 0xdf, 0x32, 0x9c, 0xa9, 0xfd, 0xbf,
0xb8, 0x34, 0x6f, 0x57, 0x17, 0xe6, 0x04, 0x37, 0x71, 0x07, 0xc0, 0xe9, 0x0f, 0x3c, 0xed, 0x4f,
0x31, 0x87, 0x05, 0xa4, 0xed, 0xab, 0xac, 0xd6, 0x50, 0x05, 0x5b, 0xca, 0xd3, 0xf9, 0xd6, 0xaa,
0xaa, 0x88, 0x57, 0x66, 0xf6, 0x6d, 0x8d, 0x4b, 0x71, 0x29, 0xd4, 0x3d, 0x1d, 0xbc, 0x82, 0x6e,
0x81, 0xe9, 0x19, 0xf5, 0xe1, 0x12, 0x9f, 0x47, 0xdb, 0x5c, 0xed, 0x88, 0xba, 0x51, 0xe7, 0x3a,
0xa0, 0x77, 0x2d, 0xe6, 0xcc, 0xb4, 0x34, 0xdf, 0xad, 0xbd, 0x7b, 0xf8, 0xa7, 0x79, 0x51, 0x2d,
0xe6, 0xc2, 0xee, 0xd2, 0x96, 0xfa, 0x60, 0x60, 0x32, 0x40, 0x41, 0x37, 0x12, 0xeb, 0x63, 0x99,
0x3d, 0xf3, 0x21, 0xbe, 0xdf, 0xa1, 0x77, 0xe6, 0x81, 0xa9, 0x99, 0x0c, 0x4b, 0x43, 0x0c, 0x05,
0x6a, 0x6b, 0x8f, 0x05, 0x02, 0xd9, 0x43, 0xab, 0x72, 0x76, 0xca, 0xa7, 0x75, 0x63, 0x85, 0xe3,
0xa5, 0x5c, 0xc0, 0xd6, 0xd4, 0x1c, 0xeb, 0xac, 0x2c, 0x9a, 0x15, 0x6b, 0x4e, 0x99, 0x74, 0x7d,
0xd2, 0x69, 0x9f, 0xa8, 0xf7, 0x65, 0xde, 0xeb, 0x36, 0x85, 0xd5, 0x7e, 0x4a, 0x7a, 0x8a, 0xeb,
0x7c, 0xcd, 0x43, 0x9e, 0x05, 0xdb, 0x34, 0xc3, 0x69, 0xbd, 0xc2, 0xe7, 0xfb, 0xa0, 0x43, 0xb3,
0xd7, 0x15, 0x28, 0x8a, 0x91, 0xce, 0xd7, 0xa7, 0xa4, 0xcc, 0xf4, 0x1b, 0x37, 0x33, 0x76, 0xc4,
0x58, 0xb9, 0x2d, 0x89, 0xe2, 0xb6, 0x2c, 0x56, 0x10, 0x96, 0xcc, 0xa6, 0x07, 0x79, 0x11, 0x7d,
0x26, 0xd2, 0x85, 0x22, 0x19, 0x20, 0xb7, 0xef, 0xc3, 0xd9, 0x4e, 0x18, 0xf3, 0xaa, 0x05, 0xce,
0x87, 0x99, 0xde, 0x76, 0x90, 0x08, 0x74, 0xac, 0x61, 0x31, 0xf8, 0x51, 0xa0, 0xc9, 0x70, 0xfc,
0xb9, 0x22, 0xfe, 0xd2, 0x0d, 0xc8, 0x49, 0x64, 0x00, 0xe4, 0xf1, 0x53, 0xfd, 0xa1, 0xe6, 0xff,
0x8e, 0xd6, 0xde, 0x9e, 0xcc, 0x3d, 0x37, 0x3a, 0x10, 0x62, 0x59, 0xb2, 0x34, 0x8a, 0x1d, 0xf7,
0x9e, 0xa0, 0xbb, 0xf4, 0x53, 0xd9, 0xb8, 0x18, 0x88, 0x12, 0x5c, 0x92, 0x0d, 0xc9, 0x94, 0x7f,
0x24, 0xb9, 0x9f, 0xda, 0x07, 0xb6, 0x79, 0x77, 0x09, 0xa3, 0x29, 0x3a, 0x70, 0x63, 0x3b, 0x22,
0x42, 0x14, 0xd0, 0xf9, 0x7b, 0x90, 0x52, 0x2b, 0x3f, 0x7f, 0xb7, 0x41, 0x20, 0x0d, 0x7e, 0x70,
0xd7, 0x88, 0x36, 0xa2, 0xe9, 0x81, 0x77, 0xf4, 0xb0, 0x15, 0x43, 0x9c, 0x5f, 0x4d, 0x3e, 0x4f,
0x83, 0x79, 0x06, 0x73, 0x7a, 0xe7, 0xcb, 0x79, 0x1d, 0xec, 0xa3, 0xce, 0x93, 0x5c, 0x68, 0xbf,
0x5a, 0xe6, 0x4c, 0x23, 0x86, 0x41, 0x7f, 0xb4, 0xfc, 0xd0, 0x2c, 0x1b, 0x64, 0x39, 0x64, 0xb7,
0xd2, 0x1d, 0xd0, 0x2d, 0x16, 0x77, 0xfe, 0x4d, 0xad, 0xf0, 0x4f, 0x38, 0xb3, 0xf9, 0x5a, 0xee,
0x0e, 0x1d, 0xb6, 0xf9, 0x3f, 0xba, 0x77, 0x5a, 0x20, 0xd2, 0x74, 0x1a, 0x4b, 0x5a, 0xaf, 0x62,
0xb5, 0xd3, 0xef, 0x37, 0x49, 0xfe, 0x1e, 0xcd, 0xb5, 0xba, 0xb5, 0xa6, 0x46, 0x7b, 0x38, 0x63,
0x62, 0x3c, 0x18, 0x7d, 0x57, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x02, 0x3c, 0x30, 0x82,
0x02, 0x38, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x35, 0x07, 0x82,
0xfe, 0x0e, 0x8f, 0xf5, 0xa0, 0x7c, 0x2e, 0xf9, 0x65, 0x7b, 0xa8, 0x48, 0xe8, 0x8f, 0x61, 0xb6,
0x1c, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x35,
0x07, 0x82, 0xfe, 0x0e, 0x8f, 0xf5, 0xa0, 0x7c, 0x2e, 0xf9, 0x65, 0x7b, 0xa8, 0x48, 0xe8, 0x8f,
0x61, 0xb6, 0x1c, 0x30, 0x82, 0x01, 0xd3, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x82, 0x01, 0xca,
0x30, 0x82, 0x01, 0xc6, 0x30, 0x82, 0x01, 0xc2, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x63,
0x64, 0x05, 0x01, 0x30, 0x82, 0x01, 0xb3, 0x30, 0x82, 0x01, 0x78, 0x06, 0x08, 0x2b, 0x06, 0x01,
0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x82, 0x01, 0x6a, 0x1e, 0x82, 0x01, 0x66, 0x00, 0x52, 0x00,
0x65, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00,
0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00,
0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00,
0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x62, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00,
0x6e, 0x00, 0x79, 0x00, 0x20, 0x00, 0x70, 0x00, 0x61, 0x00, 0x72, 0x00, 0x74, 0x00, 0x79, 0x00,
0x20, 0x00, 0x61, 0x00, 0x73, 0x00, 0x73, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x73, 0x00,
0x20, 0x00, 0x61, 0x00, 0x63, 0x00, 0x63, 0x00, 0x65, 0x00, 0x70, 0x00, 0x74, 0x00, 0x61, 0x00,
0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x74, 0x00,
0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00,
0x61, 0x00, 0x70, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x62, 0x00,
0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00,
0x61, 0x00, 0x72, 0x00, 0x64, 0x00, 0x20, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6d, 0x00,
0x73, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x63, 0x00, 0x6f, 0x00,
0x6e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x73, 0x00,
0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x65, 0x00, 0x2c, 0x00,
0x20, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00,
0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x6c, 0x00,
0x69, 0x00, 0x63, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00,
0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00,
0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x70, 0x00, 0x72, 0x00,
0x61, 0x00, 0x63, 0x00, 0x74, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73, 0x00,
0x74, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00,
0x73, 0x00, 0x2e, 0x30, 0x35, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16,
0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x70, 0x70, 0x6c,
0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
0x65, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x6f, 0x8a,
0xb7, 0x35, 0x73, 0x5a, 0xc5, 0x34, 0xf7, 0x8c, 0xf0, 0xd1, 0x4a, 0x17, 0x52, 0x1c, 0x70, 0xf0,
0xe0, 0x53, 0xb4, 0x16, 0xde, 0x81, 0xda, 0x2a, 0xa4, 0xf9, 0x5b, 0x0e, 0xa6, 0x17, 0x86, 0x52,
0xc6, 0x70, 0x73, 0xf3, 0x3f, 0x1c, 0x87, 0x94, 0xdd, 0xfe, 0x02, 0x0b, 0x85, 0xc9, 0xb9, 0xcf,
0x15, 0x91, 0x05, 0x2e, 0x7e, 0xeb, 0xe6, 0xce, 0x0e, 0x4e, 0xd1, 0xf7, 0xe2, 0xd7, 0xf4, 0x60,
0xd2, 0xfc, 0x1d, 0xbf, 0xad, 0x61, 0x28, 0xf8, 0x53, 0x31, 0xb3, 0x92, 0xef, 0xa4, 0x05, 0x34,
0x97, 0x57, 0x97, 0x56, 0x3b, 0x12, 0x20, 0x2d, 0x88, 0x76, 0x81, 0x0e, 0x77, 0x85, 0xf1, 0x37,
0xc6, 0x19, 0x8b, 0x23, 0xc2, 0x42, 0x55, 0x40, 0xc9, 0x91, 0x5c, 0x78, 0xc5, 0xe6, 0x77, 0xfe,
0x72, 0x5f, 0xb2, 0x2c, 0x00, 0xf2, 0xe6, 0x8c, 0xcc, 0x02, 0x49, 0xd9, 0x78, 0x20, 0xae, 0xbd,
0x75, 0x61, 0x6a, 0xaa, 0xc5, 0x71, 0x3e, 0x5d, 0x02, 0xdf, 0xd2, 0x91, 0x5c, 0x0a, 0x85, 0xc9,
0x59, 0x7d, 0x4e, 0x89, 0x21, 0x59, 0x59, 0xe3, 0xc7, 0xdc, 0xff, 0x1e, 0x62, 0x1e, 0xb9, 0x62,
0x2c, 0x34, 0x49, 0x15, 0xd9, 0xdf, 0x47, 0x99, 0x39, 0xcc, 0x1a, 0x01, 0xc0, 0xda, 0x48, 0x44,
0xd4, 0x8b, 0xd3, 0x17, 0x7e, 0x39, 0xf9, 0x00, 0xe1, 0x2a, 0x46, 0xaa, 0x14, 0x22, 0xa1, 0x38,
0x09, 0x0b, 0xb7, 0x0c, 0x88, 0xa5, 0x73, 0xfd, 0xc4, 0x6b, 0xee, 0x07, 0xb4, 0x1b, 0xb3, 0x4a,
0xab, 0xae, 0xf6, 0xe7, 0x04, 0x61, 0x4b, 0x34, 0x7a, 0xe4, 0xff, 0xf9, 0x30, 0x28, 0x61, 0x92,
0x52, 0x58, 0x10, 0x15, 0x3a, 0x9f, 0x0a, 0xaf, 0x15, 0x29, 0x6c, 0x67, 0xc4, 0xb4, 0xcf, 0xe6,
0xf9, 0x46, 0x68, 0xe2, 0x2a, 0x97, 0x29, 0x16, 0xed, 0x1a, 0x9b, 0x9a, 0x45, 0x70, 0x3c, 0xf2,
0xdf, 0x29, 0x20, 0x9e, 0x33, 0x4b, 0x5b, 0x8d, 0xf6, 0x19, 0xec, 0x4b, 0xae, 0x1a, 0x2f, 0x53,
0x03, 0x9a, 0xfd, 0x68, 0x39, 0x58, 0xf7, 0x2e, 0x07, 0x9c, 0xf1, 0x3c, 0x1b, 0x47, 0x43, 0x19,
0x81, 0x0e, 0x0a, 0xbb, 0x84, 0xa0, 0xda, 0x87, 0xbc, 0x8a, 0x2a, 0xb7, 0x9c, 0xe1, 0xf9, 0xeb,
0x37, 0xb0, 0x11, 0x20, 0x7e, 0x4c, 0x11, 0x2e, 0x54, 0x30, 0xce, 0xaf, 0x63, 0xed, 0x6a, 0x63,
0x1f, 0x1e, 0x61, 0x62, 0x04, 0xf3, 0x3a, 0x5f, 0x26, 0x6c, 0x5c, 0xd7, 0xba, 0x4f, 0xf2, 0x61,
0x26, 0x29, 0x99, 0xea, 0x61, 0x84, 0x0d, 0x68, 0xa2, 0x5d, 0x9b, 0x5c, 0xe7, 0x86, 0x1d, 0xef,
0xf4, 0x6f, 0x3b, 0x6c, 0x67, 0xf0, 0x70, 0xe9, 0xc5, 0xdc, 0x0a, 0x9d, 0x0f, 0xdc, 0xcc, 0x0e,
0x7b, 0xf8, 0xc4, 0xee, 0x64, 0xe4, 0xd9, 0x3f, 0x14, 0xae, 0x8f, 0xc8, 0x18, 0x4d, 0xa1, 0xe4,
0x40, 0x2c, 0xe9, 0x13, 0xc6, 0xc1, 0xe0, 0xb9, 0x13, 0xbe, 0xd9, 0x93, 0x66, 0x56, 0x35, 0x5c,
0xc1, 0x38, 0x7d, 0xa1, 0xbb, 0x87, 0xa5, 0x90, 0x33, 0x4f, 0xea, 0xb6, 0x37, 0x19, 0x61, 0x81,
0x40, 0xba, 0xd7, 0x07, 0x69, 0x05, 0x15, 0x96, 0xe9, 0xde, 0x4f, 0x8a, 0x2b, 0x99, 0x5a, 0x17,
0x3f, 0x9f, 0xcf, 0x86, 0xf5, 0x37, 0x0a, 0xa1, 0x0e, 0x25, 0x65, 0x2d, 0x52, 0xce, 0x87, 0x10,
0x0f, 0x25, 0xc2, 0x1e, 0x0f, 0x71, 0x93, 0xb5, 0xc0, 0xb3, 0xb4, 0xd1, 0x65, 0xa8, 0xb4, 0xf6,
0xa5, 0x71, 0xad, 0x45, 0xdb, 0xdf, 0xec, 0xe3, 0x2a, 0x7e, 0x99, 0x96, 0x5a, 0x5d, 0x69, 0xfa,
0xdb, 0x13, 0x39, 0xb8, 0xf5, 0x58, 0xbb, 0x87, 0x69, 0x8d, 0x2c, 0x6d, 0x39, 0xff, 0x26, 0xce,
0x2c, 0xa8, 0x5a, 0x7e, 0x4b, 0x3f, 0xed, 0xac, 0x5f, 0xf0, 0xef, 0x48, 0xd3, 0xf8
};
static const UInt8 kAppleTestPKISettingsRootCACert[] = {
0x30, 0x82, 0x05, 0xd7, 0x30, 0x82, 0x03, 0xbf, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x26,
0xfe, 0xf8, 0xda, 0x41, 0xf3, 0x61, 0x90, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00, 0x30, 0x79, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04,
0x03, 0x0c, 0x24, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65, 0x74,
0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20,
0x54, 0x45, 0x53, 0x54, 0x49, 0x4e, 0x47, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b,
0x0c, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20,
0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
0x53, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x34, 0x32, 0x32, 0x32, 0x30, 0x33, 0x31, 0x34,
0x36, 0x5a, 0x17, 0x0d, 0x34, 0x33, 0x30, 0x34, 0x31, 0x35, 0x32, 0x30, 0x33, 0x31, 0x34, 0x36,
0x5a, 0x30, 0x79, 0x31, 0x2d, 0x30, 0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x24, 0x41, 0x70,
0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x20, 0x2d, 0x20, 0x54, 0x45, 0x53, 0x54, 0x49,
0x4e, 0x47, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70, 0x70,
0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x30, 0x82, 0x02, 0x22,
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0x84, 0xbe, 0xc2,
0x69, 0x9b, 0xec, 0xd5, 0xde, 0x72, 0xf0, 0x4f, 0x78, 0x81, 0x10, 0xa9, 0x56, 0x59, 0x77, 0x9c,
0x46, 0x95, 0xd7, 0xb7, 0x0b, 0x77, 0x73, 0x02, 0xce, 0xf8, 0xaa, 0x32, 0x89, 0xee, 0xbe, 0xaa,
0x40, 0x53, 0xf9, 0x2d, 0x96, 0x08, 0xcd, 0x2a, 0xa4, 0x61, 0xd4, 0xfd, 0x7d, 0x67, 0x2a, 0x35,
0xc1, 0xfc, 0x43, 0xa4, 0x9c, 0xd0, 0xbd, 0xcd, 0x82, 0x27, 0xed, 0xa1, 0x1c, 0x2d, 0x9a, 0x62,
0xd5, 0x99, 0xbd, 0x74, 0xaa, 0xf3, 0xce, 0x78, 0xc6, 0x47, 0x07, 0x43, 0x04, 0x5b, 0xbc, 0x27,
0x5e, 0x26, 0x3e, 0x77, 0x90, 0x69, 0x7a, 0xf6, 0xe0, 0x8e, 0xaa, 0xdf, 0x96, 0x12, 0x2c, 0xb2,
0x8b, 0xb9, 0x7e, 0x17, 0xfe, 0xde, 0x99, 0x67, 0x9b, 0x50, 0x13, 0x5c, 0x8d, 0x15, 0x26, 0x0a,
0x9f, 0x08, 0x2f, 0x3f, 0x7c, 0x01, 0x2c, 0x3e, 0xa1, 0xba, 0xb1, 0x25, 0x33, 0xe5, 0xd9, 0x39,
0x37, 0xde, 0x06, 0x3a, 0x63, 0x48, 0xa0, 0x9d, 0x3b, 0xa5, 0x72, 0x46, 0xfb, 0x6e, 0xa2, 0xd4,
0x74, 0xe6, 0xf1, 0xc1, 0x69, 0xc8, 0x31, 0xff, 0x58, 0x84, 0x3a, 0xc2, 0x6b, 0x9a, 0x0d, 0x19,
0x76, 0xe4, 0xd4, 0x4d, 0x85, 0xbc, 0x84, 0xf0, 0x07, 0x75, 0x66, 0x5f, 0xd7, 0xea, 0xab, 0x9e,
0x46, 0xf2, 0x8a, 0x29, 0xab, 0x73, 0x57, 0xaf, 0x95, 0x4f, 0xc7, 0xf3, 0x3b, 0x55, 0xb4, 0x26,
0x57, 0x68, 0xe9, 0x5a, 0x34, 0xbb, 0xa9, 0x39, 0xb3, 0x57, 0x5f, 0x25, 0x93, 0xd6, 0x34, 0xb7,
0xd1, 0xc4, 0xd7, 0x70, 0xed, 0x30, 0xdb, 0x21, 0xc1, 0xcc, 0xdf, 0xed, 0xec, 0x37, 0xc5, 0xdc,
0x0b, 0xc9, 0x85, 0x46, 0x26, 0xa7, 0x51, 0xc8, 0xdd, 0xe6, 0x47, 0xfc, 0x37, 0xd6, 0x73, 0x6f,
0x91, 0x3d, 0xef, 0xd8, 0xa4, 0xa5, 0x08, 0x32, 0x8c, 0xae, 0x8f, 0x57, 0xf7, 0x99, 0x48, 0xef,
0x81, 0x44, 0xac, 0x80, 0x42, 0x57, 0x9f, 0x64, 0x77, 0x40, 0x2a, 0xec, 0x03, 0x21, 0x79, 0x01,
0x0b, 0x87, 0xc3, 0x9d, 0x22, 0xc9, 0xc0, 0x69, 0xe0, 0x34, 0xff, 0x73, 0xdd, 0x1e, 0x1b, 0x0c,
0xe0, 0x68, 0xf0, 0x8c, 0x7a, 0x4b, 0xcd, 0x1d, 0x3f, 0x38, 0x2d, 0xe8, 0x9b, 0x91, 0xa6, 0xfe,
0xa8, 0x8b, 0x45, 0x1c, 0xdf, 0xaf, 0x49, 0x34, 0x48, 0x17, 0x02, 0x28, 0xdb, 0xe0, 0x6e, 0x74,
0x34, 0xea, 0xac, 0x6b, 0x00, 0x45, 0x89, 0xa9, 0xb5, 0x63, 0xbd, 0x2f, 0xe0, 0x58, 0x2e, 0xd3,
0xc2, 0x74, 0xa2, 0x37, 0x37, 0x62, 0xf6, 0x76, 0x1b, 0x3f, 0xfb, 0x98, 0x64, 0x13, 0xd6, 0x8c,
0xa0, 0x0c, 0xbc, 0x54, 0x00, 0xe0, 0xf8, 0x63, 0x17, 0x22, 0x44, 0x36, 0xe0, 0x28, 0xa0, 0x7d,
0x50, 0x9e, 0x50, 0x94, 0xea, 0xd7, 0x62, 0xab, 0x6d, 0x7a, 0x19, 0xa4, 0xa2, 0x74, 0x79, 0x5d,
0x15, 0x85, 0x21, 0xfe, 0x9a, 0x35, 0x76, 0x40, 0x78, 0x01, 0xe3, 0x46, 0x2f, 0x6f, 0x2d, 0x0a,
0x1d, 0xac, 0x2e, 0x23, 0xec, 0xb8, 0x48, 0x74, 0xbc, 0xee, 0x29, 0x72, 0xb6, 0xe7, 0x52, 0x8c,
0xd4, 0x1a, 0x00, 0x34, 0x75, 0x1c, 0x4b, 0x83, 0x50, 0xbb, 0x57, 0x21, 0x9b, 0xd8, 0xb4, 0x75,
0xf3, 0x98, 0x8a, 0x9b, 0x45, 0xa8, 0x61, 0x50, 0x10, 0xb4, 0xec, 0x91, 0x2e, 0xe7, 0xf2, 0xb8,
0xb9, 0x62, 0x70, 0xc2, 0x93, 0xe7, 0xd9, 0xf1, 0x02, 0x27, 0xd7, 0xec, 0xde, 0x5b, 0x42, 0xa1,
0x26, 0x37, 0x41, 0x32, 0x65, 0x11, 0x63, 0x38, 0xbb, 0x6f, 0x23, 0x7a, 0xa0, 0xb7, 0x24, 0xeb,
0xa8, 0x38, 0x8b, 0xa7, 0x73, 0xe2, 0xc8, 0x30, 0x56, 0x73, 0x6f, 0x17, 0x6e, 0x1a, 0xe5, 0x32,
0xff, 0xd6, 0xa2, 0x08, 0x7b, 0x6a, 0x23, 0x33, 0x9f, 0x10, 0x05, 0x71, 0xdd, 0x02, 0x03, 0x01,
0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
0x14, 0xd2, 0xa5, 0x3b, 0xf2, 0x5d, 0xfd, 0x1f, 0x25, 0xda, 0xfb, 0x06, 0xfb, 0x59, 0x99, 0xc4,
0xac, 0xc4, 0x0b, 0xac, 0x64, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
0x16, 0x80, 0x14, 0xd2, 0xa5, 0x3b, 0xf2, 0x5d, 0xfd, 0x1f, 0x25, 0xda, 0xfb, 0x06, 0xfb, 0x59,
0x99, 0xc4, 0xac, 0xc4, 0x0b, 0xac, 0x64, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x71, 0x10, 0x3c, 0x89, 0xd5,
0xc0, 0x00, 0xdc, 0x36, 0x1d, 0x93, 0xaa, 0xab, 0x4a, 0xb6, 0xfa, 0xa8, 0x5b, 0x89, 0x1c, 0xb3,
0x4a, 0x04, 0x2e, 0xb3, 0x25, 0x0f, 0x12, 0x07, 0x29, 0x70, 0x3d, 0x34, 0xd1, 0xdd, 0x7e, 0x30,
0xfd, 0xf5, 0xfa, 0x94, 0xf4, 0xcb, 0xdb, 0xac, 0x1b, 0xed, 0xe5, 0x11, 0x4a, 0xc8, 0xab, 0x26,
0xe2, 0x41, 0xcb, 0xa5, 0x74, 0x4b, 0xe1, 0xd2, 0xf3, 0x83, 0x1c, 0x7a, 0xcb, 0x29, 0xd9, 0xd2,
0xa6, 0x9d, 0x08, 0x95, 0x73, 0x63, 0xe2, 0x9c, 0xeb, 0xa5, 0x82, 0x8b, 0x6c, 0xf4, 0x64, 0x98,
0x03, 0x53, 0x91, 0x35, 0x04, 0x89, 0x25, 0xa0, 0x1f, 0xdc, 0x42, 0xf7, 0x59, 0x44, 0x63, 0x75,
0xe6, 0x49, 0x10, 0x66, 0x0f, 0x08, 0x07, 0x39, 0xc4, 0x3e, 0x1f, 0xba, 0x30, 0x42, 0xf8, 0x7a,
0xc8, 0xbe, 0x6f, 0xdb, 0xec, 0x16, 0xb2, 0x76, 0x84, 0x2c, 0x6e, 0x20, 0xd1, 0xbd, 0xd5, 0x90,
0x22, 0x0a, 0x90, 0x5c, 0x70, 0x47, 0xc9, 0x2d, 0xe3, 0x77, 0x74, 0xfd, 0xbb, 0x85, 0x1a, 0xd8,
0x5c, 0x38, 0x94, 0x4c, 0x83, 0x28, 0x23, 0xa5, 0x4f, 0x55, 0x5f, 0xe3, 0x42, 0x80, 0x10, 0xd4,
0xa5, 0x8d, 0xcf, 0x8b, 0x53, 0x69, 0x6d, 0xc5, 0x37, 0xd2, 0xfa, 0xbb, 0xc0, 0x5a, 0xab, 0x6f,
0x71, 0x37, 0x92, 0xd4, 0x90, 0xef, 0x5d, 0xf1, 0xc3, 0xb8, 0x64, 0x08, 0xd3, 0xba, 0x36, 0x69,
0x2b, 0x00, 0xed, 0xad, 0x36, 0x21, 0x38, 0xdf, 0x4a, 0xc6, 0x44, 0xc4, 0x6b, 0xd8, 0xb0, 0x7f,
0x67, 0x05, 0xaa, 0x6f, 0x9e, 0x8a, 0xf1, 0x81, 0x95, 0x99, 0xb9, 0x56, 0xf4, 0x73, 0xa7, 0xb4,
0x19, 0xb9, 0x4b, 0xb8, 0x1d, 0x10, 0xa5, 0x88, 0x7c, 0x39, 0xa3, 0x85, 0xe7, 0xba, 0x65, 0x86,
0xca, 0xf7, 0x0e, 0xe0, 0x0d, 0x73, 0x3f, 0xea, 0x98, 0x88, 0x58, 0x73, 0xfa, 0x68, 0x5b, 0xaa,
0x8c, 0xfd, 0x3e, 0x22, 0x3e, 0x92, 0xc7, 0xe2, 0x77, 0x14, 0x81, 0xe6, 0xd9, 0xdc, 0xc1, 0xe9,
0xc0, 0x06, 0x57, 0xb4, 0xca, 0xb6, 0x14, 0x15, 0x16, 0x80, 0x7e, 0xc5, 0x11, 0xa4, 0x05, 0x66,
0xad, 0x1d, 0xa3, 0xb6, 0xab, 0x2a, 0xbe, 0xd0, 0x52, 0x4e, 0x9e, 0x84, 0x61, 0x6b, 0xf4, 0x34,
0x23, 0x94, 0x24, 0xc6, 0xc8, 0xb0, 0x94, 0x22, 0x4c, 0x3b, 0xac, 0x85, 0xe3, 0xd4, 0xf7, 0x38,
0xe5, 0x9a, 0x76, 0xb3, 0x1b, 0xf0, 0xbc, 0x78, 0xc6, 0x6f, 0x11, 0xb3, 0x1a, 0x5c, 0x4f, 0x07,
0x52, 0x06, 0x92, 0x7a, 0x25, 0x86, 0x91, 0x71, 0x8a, 0xf4, 0x03, 0xce, 0x19, 0x0d, 0xfc, 0xde,
0x8f, 0xc9, 0x4e, 0x84, 0xf1, 0x17, 0x18, 0x6f, 0x37, 0x56, 0xb9, 0x76, 0x7e, 0x8f, 0xca, 0xde,
0xd4, 0x1b, 0x2d, 0x8d, 0xcf, 0x12, 0x9f, 0xf9, 0xb9, 0x8b, 0x82, 0x8f, 0x4d, 0xb7, 0x63, 0x26,
0x8d, 0xda, 0x35, 0x94, 0x18, 0xf9, 0x55, 0xca, 0x39, 0x09, 0xe9, 0x62, 0xe1, 0x00, 0xd8, 0x67,
0xed, 0x5e, 0x84, 0xc2, 0xe5, 0x8e, 0x46, 0x57, 0xa4, 0xa7, 0x17, 0x70, 0xcf, 0x6d, 0xdf, 0x43,
0x64, 0x2b, 0x36, 0xe6, 0xf3, 0xc1, 0x4c, 0x7a, 0x7e, 0x9e, 0x47, 0xc4, 0x14, 0x82, 0xbe, 0x94,
0x73, 0x54, 0xd0, 0x2c, 0xc2, 0x31, 0xc6, 0xd5, 0xc3, 0xd7, 0xa9, 0xef, 0x11, 0x24, 0x2f, 0xd0,
0x5b, 0xb8, 0x6a, 0x8e, 0x3c, 0xb7, 0x4b, 0x00, 0x9b, 0xc1, 0xca, 0x00, 0x6f, 0xd4, 0x73, 0x93,
0x2e, 0x39, 0x37, 0x2a, 0x73, 0x44, 0x9b, 0x1b, 0x05, 0x1a, 0x7c, 0x2f, 0xc9, 0x2b, 0x37, 0xf3,
0xcd, 0x8c, 0x4e, 0xc2, 0x7a, 0x6e, 0xd9, 0xd4, 0xf1, 0x8d, 0x6d, 0x07, 0x4b, 0xb5, 0x09, 0xb9,
0x48, 0x55, 0xac, 0xc6, 0x7e, 0xbc, 0xc6, 0x76, 0xeb, 0x5f, 0x0f
};
static NSDictionary* VerifyMessage(CFDataRef message, SecPolicyRef policy, CFDataRef cert_data)
{
NSDictionary* result = nil;
SecTrustRef trustRef = NULL;
CFDataRef payload = NULL;
CFArrayRef anchors = NULL;
OSStatus status = noErr;
SecCertificateRef aCertRef = NULL;
SecTrustResultType trust_result = kSecTrustResultRecoverableTrustFailure;
if (NULL == message || NULL == policy || NULL == cert_data)
{
goto out;
}
status = SecCMSVerifyCopyDataAndAttributes(message, NULL, policy, &trustRef, &payload, NULL);
if (noErr != status || NULL == trustRef || NULL == payload)
{
goto out;
}
aCertRef = SecCertificateCreateWithData(NULL, cert_data);
if (NULL == aCertRef)
{
goto out;
}
anchors = CFArrayCreate(kCFAllocatorDefault, (const void **)&aCertRef, 1, &kCFTypeArrayCallBacks);
if (NULL == anchors)
{
goto out;
}
status = SecTrustSetAnchorCertificates(trustRef, anchors);
if (noErr != status)
{
goto out;
}
status = SecTrustEvaluate(trustRef, &trust_result);
if (noErr != status)
{
goto out;
}
if (trust_result == kSecTrustResultUnspecified)
{
// Life is good and we got back the expected result.
NSData* property_list_data = CFBridgingRelease(payload);
NSPropertyListFormat format;
NSError* error = nil;
result = [NSPropertyListSerialization propertyListWithData:property_list_data options:0 format:&format error:&error];
if (nil != error)
{
result = nil;
}
}
out:
CFReleaseSafe(aCertRef)
CFReleaseSafe(anchors);
return result;
}
/* ==========================================================================
Private Methods for the OTAServiceApp class
========================================================================== */
@interface OTAServiceApp (PrivateMethods)
- (void)processAssets:(NSArray*)assets;
- (BOOL)checkAssetVersions:(NSString *)assetDir;
- (BOOL)validateAsset:(NSString *)assetDir;
- (BOOL)validateDirectory:(NSString *)assetDir withFiles:(NSArray *)file_names;
- (NSDictionary *)decodeManifest:(NSData *)manifest_file_data;
- (BOOL)checkFileHash:(NSString *)file_path hash:(NSData *)hash;
- (BOOL)installAssetFiles:(NSString *)assetDir;
- (NSString*)getCurrentAssetDirectory;
@end
@implementation OTAServiceApp
@synthesize file_list = _file_list;
@synthesize manifest_file_name = _manifest_file_name;
@synthesize asset_version_file_name = _asset_version_file_name;
@synthesize current_asset_version = _current_asset_version;
@synthesize next_asset_version = _next_asset_version;
@synthesize fileManager = _fileManager;
@synthesize current_asset_directory = _current_asset_directory;
@synthesize assets_directory = _assets_directory;
/* --------------------------------------------------------------------------
OTAServiceApp init:withArguments:
Initialize a new instance of the OTAServiceApp class
-------------------------------------------------------------------------- */
- (id)init:(int)argc withArguments:(const char**)argv
{
if ((self = [super init]))
{
_fileManager = [NSFileManager defaultManager];
_manifest_file_name = (NSString *)kManifestFileName;
_asset_version_file_name = (NSString *)kAssetVersionFileName;
_file_list = [NSArray arrayWithObjects:kBlockKeyFileName, kGrayListedKeysFileName,
kEVRootsFileName, kCertsIndexFileName, kCertsTableFileName,
kManifestFileName, kAssetVersionFileName, kAppleESCertificatesName,
kAllowListFileName, kCTLogsFileName, nil];
_current_asset_version = nil;
_next_asset_version = nil;
_assets_directory = nil;
_current_asset_directory = [self getCurrentAssetDirectory];
/* Default interval is one hour */
_asset_query_retry_interval = 60.0 * 60;
_verbose = false;
int ch;
while ((ch = getopt(argc, (char * const *)argv, "d:v")) != -1 )
{
switch (ch)
{
case 'd':
{
char *endptr = NULL;
errno = 0;
CFTimeInterval interval = strtod(optarg, &endptr);
if ((interval == 0 && endptr == optarg) || errno == ERANGE) {
syslog(LOG_ERR, "invalid argument '%s', ignoring", optarg);
} else {
syslog(LOG_NOTICE, "Setting query retry interval to _asset_query_retry_interval = (CFTimeInterval)interval;
}
}
break;
case 'v':
syslog(LOG_NOTICE, "Enabling verbose logging");
_verbose = true;
break;
default:
break;
}
}
struct stat info;
#if NEW_LOCATION
if (stat([kBaseAssetDirectoryPath UTF8String], &info))
{
OTAPKI_LOG("OTAServiceApp.init:withArguments: stat of
if (mkdir([kBaseAssetDirectoryPath UTF8String], kAssetDirectoryPermission))
{
OTAPKI_LOG("OTAServiceApp.init:withArguments: mkdir of }
else
{
if (stat([kBaseAssetDirectoryPath UTF8String], &info))
{
OTAPKI_LOG("OTAServiceApp.init:withArguments: second stat of }
}
}
#else
stat([kBaseAssetDirectoryPath UTF8String], &info);
_uid = info.st_uid;
_gid = info.st_gid;
#endif
}
return self;
}
#if !TARGET_IPHONE_SIMULATOR
- (void)registerBackgroundTaskAgentJobWithDelay:(CFTimeInterval)delay
{
/*
* ELEs are very important, so allow asset queries on any network type and
* construct the job so that it will fire as soon as possible, unless we are
* scheduling a retry after a failure.
*/
xpc_object_t job = xpc_dictionary_create(NULL, NULL, 0);
if (delay != 0)
{
xpc_dictionary_set_double(job, kBackgroundTaskAgentJobWindowStartTime, CFAbsoluteTimeGetCurrent() + delay);
}
xpc_dictionary_set_double(job, kBackgroundTaskAgentJobWindowEndTime, CFAbsoluteTimeGetCurrent() + BACKGROUND_TASK_AGENT_JOB_WINDOW_MAX_TIME_FROM_NOW_SEC);
xpc_dictionary_set_bool(job, kBackgroundTaskAgentNetworkRequired, true);
xpc_dictionary_set_bool(job, kBackgroundTaskAgentCellularAllowed, true);
xpc_dictionary_set_bool(job, kBackgroundTaskAgentAllowedDuringRoaming, true);
xpc_dictionary_set_bool(job, kBackgroundTaskAgentPowerOptLevel, kBackgroundTaskAgentPowerDontCare);
if (_verbose)
{
char *desc = xpc_copy_description(job);
syslog(LOG_NOTICE, "Adding BTA job free(desc);
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
BackgroundTaskAgentAddJob(kOTAPKIAssetToolBTAJob, job);
#pragma GCC diagnostic pop
}
#endif
/* --------------------------------------------------------------------------
OTAServiceApp checkInWithActivity
Check in with the XPC activity configured in OTAPKIAssetTool's launchd
plist. This activity will launch OTAPKIAssetTool every three days (with
some leeway decided by the system). At that time, we schedule a
BackgroundTaskAgent job to be notified immediately when the network is
available so we can perform an asset query.
-------------------------------------------------------------------------- */
- (void)checkInWithActivity
{
#if !TARGET_IPHONE_SIMULATOR
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
BackgroundTaskAgentInit("com.apple.OTAPKIAssetTool", dispatch_get_main_queue(), ^(const char *job_name, xpc_object_t job)
{
/*
* We're doing real work at this point, so open a transaction so
* that the system (hopefully) won't kill us while we're busy
*/
xpc_transaction_begin();
if (self->_verbose)
{
syslog(LOG_NOTICE, "BackgroundTaskAgent job }
int64_t job_status = xpc_dictionary_get_int64(job, kBackgroundTaskAgentJobStatus);
if (job_status == kBackgroundTaskAgentJobRequestError)
{
syslog(LOG_ERR, "Failed to create BTA job -- malformed job?");
}
else if (job_status == kBackgroundTaskAgentJobSatisfied)
{
if (self->_verbose)
{
syslog(LOG_NOTICE, "BTA job }
bool shouldReschedule = false;
if ([self run:&shouldReschedule] || !shouldReschedule)
{
if (self->_verbose)
{
syslog(LOG_NOTICE, "Unscheduling BTA job");
}
BackgroundTaskAgentRemoveJob(kOTAPKIAssetToolBTAJob);
}
else
{
syslog(LOG_NOTICE, "Asset query failed due to network error. Re-scheduling BTA job for another attempt in [self registerBackgroundTaskAgentJobWithDelay:self->_asset_query_retry_interval];
}
}
else if (job_status == kBackgroundTaskAgentJobUnsatisfied)
{
/*
* We will receive this if the job expires before we get to do our
* work. We still want to check for new assets as soon as possible,
* so reschedule the job.
*/
if (xpc_dictionary_get_bool(job, kBackgroundTaskAgentJobExpired))
{
[self registerBackgroundTaskAgentJobWithDelay:0];
}
}
xpc_transaction_end();
});
#pragma GCC diagnostic pop
#endif
xpc_activity_register(kOTAPKIAssetToolActivity, XPC_ACTIVITY_CHECK_IN, ^(xpc_activity_t activity)
{
xpc_activity_state_t state = xpc_activity_get_state(activity);
if (self->_verbose)
{
xpc_object_t criteria = xpc_activity_copy_criteria(activity);
if (criteria != NULL)
{
char *desc = xpc_copy_description(criteria);
syslog(LOG_NOTICE, "Criteria for XPC activity free(desc);
}
else
{
syslog(LOG_NOTICE, "No critera for XPC activity }
}
if (state == XPC_ACTIVITY_STATE_CHECK_IN)
{
/*
* The activity is already configured in the launchd plist, so there
* is nothing to do here
*/
if (self->_verbose)
{
syslog(LOG_NOTICE, "Activity }
}
else if (state == XPC_ACTIVITY_STATE_RUN)
{
#if !TARGET_IPHONE_SIMULATOR
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
xpc_object_t job = BackgroundTaskAgentCopyJob(kOTAPKIAssetToolBTAJob);
#pragma GCC diagnostic pop
if (job == NULL)
{
syslog(LOG_NOTICE, "Activity [self registerBackgroundTaskAgentJobWithDelay:0];
}
else if (self->_verbose)
{
syslog(LOG_NOTICE, "Already have a BTA job registered. Ignoring activity.");
}
#else
/*
* BackgroundTaskAgent doesn't exist on the iOS simulator, so we
* just directly try to find and download new assets.
*/
xpc_transaction_begin();
bool shouldReschedule = false;
if (![self run:&shouldReschedule]) {
syslog(LOG_NOTICE, "Asset query failed }
xpc_transaction_end();
#endif
}
});
}
/* --------------------------------------------------------------------------
OTAServiceApp run
Run this program and leave. This program will currently run every 3 days,
with some leeway based on network availability. That will provide the
longest time from publisihing a change in the PKI trust setting asset and
having that asset be consumed by a device.
The program simnply ask the mobile asset daemon if there are any assets
to be processed with the PKITrustDataAssetType. If not this program
will just complete and will be re-run in 3 days. If there is an asset to
process then the asset will be process and then the program will complete.
Returns false if the operation failed. On return, shouldReschedule is set
to true if the operation failed due to a network error and the caller
should reschedule this operation at a more opportune time.
-------------------------------------------------------------------------- */
- (bool)run:(bool *)shouldReschedule
{
@autoreleasepool
{
if (shouldReschedule != NULL) {
*shouldReschedule = false;
}
syslog(LOG_NOTICE, "OTAPKIAssetTool running");
if (![[MCProfileConnection sharedConnection] isOTAPKIUpdatesAllowed])
{
syslog(LOG_NOTICE, "OTAPKIAssetTool: OTAPKI updates are not allowed.");
return false;
}
ASAssetQuery *assetQuery = [[ASAssetQuery alloc] initWithAssetType:(NSString *)kPKITrustDataAssetType];
if (assetQuery == nil)
{
syslog(LOG_NOTICE, "OTAPKIAssetTool: Could not create the asset query.");
return false;
}
// Get the asset synchronously
NSError *error = nil;
NSArray *foundAssets = [assetQuery runQueryAndReturnError:&error];
if (nil != foundAssets)
{
[self processAssets:foundAssets];
}
else
{
syslog(LOG_NOTICE, "OTAPKIAssetTool: No assets returned from query:
NSArray *networkErrorCodes = @[ @(ASErrorNetwork), @(ASErrorNetworkNoConnection), @(ASErrorNetworkTimedOut), @(ASErrorNetworkUnexpectedResponse) ];
if ([[error domain] isEqualToString:ASErrorDomain] && [networkErrorCodes containsObject:@([error code])])
{
syslog(LOG_NOTICE, "OTAPKIAssetTool: Query failed due to network error.");
if (shouldReschedule != NULL) {
*shouldReschedule = true;
}
}
return false;
}
return true;
}
}
/* --------------------------------------------------------------------------
OTAServiceApp processAssets:
If when run is called asset(s) are found they will be processed here.
-------------------------------------------------------------------------- */
- (void)processAssets:(NSArray*)assets
{
if (nil == assets)
{
return;
}
NSError* error = nil;
ASAsset* asset = nil;
int asset_version = 0;
for (asset in assets)
{
NSDictionary* asset_attributes = asset.attributes;
NSNumber* contentVersion = [asset_attributes objectForKey:@"ContentVersion"];
OTAPKI_LOG("In processAssets: about to check the ContentVersion\n");
if (nil != contentVersion)
{
asset_version = [contentVersion intValue];
int current_asset_version_number = (nil != _current_asset_version) ? [_current_asset_version intValue] : 0;
if (asset_version <= current_asset_version_number)
{
syslog(LOG_NOTICE, "OTAPKIAssetTool: content version asset_version, current_asset_version_number);
OTAPKI_LOG("In processAssets: content version is too small: current asset version is current_asset_version_number, asset_version);
asset = nil;
continue;
}
}
if (nil == asset)
{
syslog(LOG_NOTICE, "OTAPKIAssetTool: no suitable asset found");
return;
}
// Check to see if the asset needs to be downloaded
if (asset.state == ASAssetStateNotPresent)
{
__block dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[asset setProgressHandler:^(NSDictionary *state, NSError *anError)
{
if (error != nil)
{
// An error occured. Signal the semaphore to bail
dispatch_semaphore_signal(sem);
}
else if ([[state objectForKey:@"Operation"] isEqualToString:(NSString *) @"OperationCompleted"])
{
// The download is complete. Signal the semaphore
dispatch_semaphore_signal(sem);
}
}];
NSNumber* yesValue = [NSNumber numberWithBool:YES];
const id keys[] = {ASDownloadOptionAllow3G, ASDownloadOptionAllow4G, ASDownloadOptionPriority, ASDownloadOptionAllowBatteryPower};
const id values[] = {yesValue, yesValue, ASDownloadPriorityHigh, yesValue};
NSDictionary* options = [NSDictionary dictionaryWithObjects:values forKeys:keys count:(sizeof (keys) / sizeof(keys[0]))];
[asset beginDownloadWithOptions:options];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}
// Check to see if the asset is now available for processing
if ([asset state] == ASAssetStateInstalled)
{
// Get the asset data directory
NSString* assetDir = [[[asset localURL] URLByAppendingPathComponent:@"PKITrustData"] path];
if (nil != assetDir)
{
// validate the asset.
OTAPKI_LOG("In processAssets: about to validateAsset\n");
if ([self validateAsset:assetDir])
{
OTAPKI_LOG("In processAssets: asset validated installing\n");
// The asset is valid so install the files
[self installAssetFiles:assetDir];
// Signal securityd to idle-exit at it's next opportunity
OTAPKI_LOG("In processAssets: notifying securityd\n");
int didUpdate = 0;
(void)SecTrustOTAPKIGetUpdatedAsset(&didUpdate);
syslog(LOG_NOTICE, "OTAPKIAssetTool: installed new asset _current_asset_version = contentVersion;
}
else
{
syslog(LOG_NOTICE, "OTAPKIAssetTool: Asset }
// regaurdless if the asset is valid. Now that it is
// installed, it needs to be purged to ensure that
// we can retrieve a new updated asset.
[asset purgeAndReturnError:&error];
}
else
{
syslog(LOG_NOTICE, "OTAPKIAssetTool: Asset directory }
}
}
}
/* --------------------------------------------------------------------------
OTAServiceApp checkAssetVersions:
If when run is called asset(s) are found they will be processed here.
-------------------------------------------------------------------------- */
- (BOOL)checkAssetVersions:(NSString *)assetDir
{
BOOL result = NO;
OTAPKI_LOG("Entering checkAssetVersions\n");
if (nil == assetDir || nil == self.current_asset_version)
{
OTAPKI_LOG("checkAssetVersions: parameter error\n");
return result;
}
// first get the new version number from the downloaded asset
NSString* next_asset_version_path = [assetDir stringByAppendingPathComponent:self.asset_version_file_name];
if (![self.fileManager fileExistsAtPath:next_asset_version_path])
{
// The asset is missing the AssertVersion.plist
// This is an invalid asset
OTAPKI_LOG("checkAssetVersions: could not file asseet version file return result;
}
NSError* error = nil;
NSInputStream* input_stream = [NSInputStream inputStreamWithFileAtPath:next_asset_version_path];
[input_stream open];
NSDictionary* asset_dict = [NSPropertyListSerialization propertyListWithStream:input_stream options:0 format:nil error:&error];
[input_stream close];
if (nil != error)
{
OTAPKI_LOG("checkAssetVersions: error reading asset version file: return result;
}
_next_asset_version = [asset_dict objectForKey:kVersionNumberKey];
if (nil == _next_asset_version)
{
OTAPKI_LOG("asset_dict did not have a entry with a key of kVersionNumberKey\n");
return result;
}
// Check the current asset version against the new asset version. The new asset version MUST be larger than the
// current asset version
NSInteger current_asset_version_value = [self.current_asset_version integerValue];
NSInteger next_asset_version_value = [self.next_asset_version integerValue];
if (next_asset_version_value <= current_asset_version_value)
{
OTAPKI_LOG("heckAssetVersions: assert version too small. current_asset_version_value = current_asset_version_value, next_asset_version_value);
return result;
}
return YES;
}
/* --------------------------------------------------------------------------
OTAServiceApp validateAsset:
Decode the manifest and verify the file hashes
-------------------------------------------------------------------------- */
- (BOOL)validateAsset:(NSString *)assetDir
{
BOOL result = NO;
OTAPKI_LOG("Enterning validateAsset\n");
if (![self validateDirectory:assetDir withFiles:self.file_list])
{
OTAPKI_LOG("validateAsset param\n");
return result;
}
NSString* manifest_file_path = [assetDir stringByAppendingPathComponent:self.manifest_file_name];
NSError* error = nil;
NSData* manifest_file_data = [NSData dataWithContentsOfFile:manifest_file_path options:0 error:&error];
if (nil != error)
{
OTAPKI_LOG("validateAsset: could not read manifest file. error = return result;
}
NSDictionary* manifest_data = [self decodeManifest:manifest_file_data];
if (nil == manifest_data)
{
OTAPKI_LOG("validateAsset: decodeManifest failed!\n");
return result;
}
NSString* full_file_path = nil;
NSData* hash = nil;
for (NSString* file_name in self.file_list)
{
if ([file_name isEqualToString:self.manifest_file_name])
{
continue;
}
hash = [manifest_data objectForKey:file_name];
if (nil == hash)
{
OTAPKI_LOG("validateAsset: could not get hash for file return result;
}
full_file_path = [assetDir stringByAppendingPathComponent:file_name];
if (![self checkFileHash:full_file_path hash:hash])
{
OTAPKI_LOG("validateAsset: hash for file return result;
}
}
result = [self checkAssetVersions:assetDir];
return result;
}
/* --------------------------------------------------------------------------
OTAServiceApp validateDirectory:withFiles:
Ensure that a given directory has the files listed in the files_names
parameter
-------------------------------------------------------------------------- */
- (BOOL)validateDirectory:(NSString *)assetDir withFiles:(NSArray *)file_names
{
BOOL result = NO;
OTAPKI_LOG("Enterning validateDirectory\n");
if (nil == assetDir || nil == file_names)
{
OTAPKI_LOG("validateDirectory param error\n");
return result;
}
NSError* error = nil;
NSArray* dir_items = [self.fileManager contentsOfDirectoryAtPath:assetDir error:&error];
if (nil != error)
{
OTAPKI_LOG("validateDirectory: Error calling contentsOfDirectoryAtPath: error = return result;
}
for (NSString* file_name in file_names)
{
if (![dir_items containsObject:file_name])
{
OTAPKI_LOG("validateDirectory: missing file return result;
}
}
return YES;
}
/* --------------------------------------------------------------------------
OTAServiceApp decodeManifest:
Ensure that the asset manifest blob has it CMS signature verified
-------------------------------------------------------------------------- */
- (NSDictionary *)decodeManifest:(NSData *)manifest_file_data
{
NSDictionary* result = nil;
CFDataRef cert_data = NULL;
CFDataRef message = NULL;
SecPolicyRef policy = NULL;
CFBooleanRef mgResult = NULL;
OTAPKI_LOG("Enterning decodeManifest\n");
if (nil == manifest_file_data)
{
OTAPKI_LOG("decodeManifest: parameter error\n");
goto out;
}
message = CFBridgingRetain(manifest_file_data);
policy = SecPolicyCreateOTAPKISigner();
if (NULL == policy)
{
OTAPKI_LOG("decodeManifest: could not get the SecPolicyCreateOTAPKISigner policyRef\n");
goto out;
}
cert_data = CFDataCreate(kCFAllocatorDefault, kApplePKISettingsRootCACert, sizeof(kApplePKISettingsRootCACert));
if (NULL == cert_data)
{
OTAPKI_LOG("decodeManifest: could not kApplePKISettingsRootCACert data\n");
goto out;
}
result = VerifyMessage(message, policy, cert_data);
if (NULL != result)
{
OTAPKI_LOG("decodeManifest: SecPolicyCreateOTAPKISigner success!\n");
goto out;
}
OTAPKI_LOG("decodeManifest: SecPolicyCreateOTAPKISigner failed! Checking to see if this is an internal build\n");
// The first attempt did not work so check to see if this is running on an internal build.
if (!MGIsQuestionValid(kMGQAppleInternalInstallCapability))
{
OTAPKI_LOG("decodeManifest: kMGQAppleInternalInstallCapability had an error\n");
goto out;
}
mgResult = MGCopyAnswer(kMGQAppleInternalInstallCapability, NULL);
if (NULL == mgResult || !CFEqual(mgResult, kCFBooleanTrue))
{
OTAPKI_LOG("decodeManifest: Not an internal build");
goto out;
}
OTAPKI_LOG("decodeManifest: This is an internal build\n");
CFReleaseNull(policy);
CFReleaseNull(cert_data);
policy = SecPolicyCreateTestOTAPKISigner();
if (NULL == policy)
{
OTAPKI_LOG("decodeManifest: could not SecPolicyCreateTestOTAPKISigner policyRef\n");
goto out;
}
cert_data = CFDataCreate(kCFAllocatorDefault, kAppleTestPKISettingsRootCACert, sizeof(kAppleTestPKISettingsRootCACert));
if (NULL == cert_data)
{
OTAPKI_LOG("decodeManifest: could not kAppleTestPKISettingsRootCACert data\n");
goto out;
}
result = VerifyMessage(message, policy, cert_data);
out:
CFReleaseSafe(mgResult);
CFReleaseSafe(message);
CFReleaseSafe(policy);
CFReleaseSafe(cert_data);
return result;
}
/* --------------------------------------------------------------------------
OTAServiceApp checkFileHash:hash:
Ensure that the given asset file's hash is the same as in the manifest
-------------------------------------------------------------------------- */
- (BOOL)checkFileHash:(NSString *)file_path hash:(NSData *)hash
{
BOOL result = NO;
if (nil == file_path || nil == hash)
{
return result;
}
NSError* error = nil;
NSData* file_data = [NSData dataWithContentsOfFile:file_path options:0 error:&error];
if (nil != error)
{
return result;
}
NSMutableData *digest = [NSMutableData dataWithLength:CC_SHA256_DIGEST_LENGTH];
uint8_t *dp = (digest) ? [digest mutableBytes] : NULL;
if (NULL == dp)
{
return result;
}
memset(dp, 0, CC_SHA256_DIGEST_LENGTH);
CCDigest(kCCDigestSHA256,
(const uint8_t *)[file_data bytes],
(size_t)[file_data length], dp);
result = [hash isEqualToData:digest];
return result;
}
/* --------------------------------------------------------------------------
OTAServiceApp installAssetFiles:
Copy over the files into the /var/Keychains/Assets directory.
-------------------------------------------------------------------------- */
- (BOOL)installAssetFiles:(NSString *)assetDir
{
BOOL result = NO;
OTAPKI_LOG("Entering installAssetFiles\n");
if (nil == assetDir)
{
OTAPKI_LOG("installAssetFiles: parameter error\n");
return result;
}
if (nil == self.assets_directory)
{
OTAPKI_LOG("installAssetFiles: no assets directory\n");
return result;
}
// Create a temp directory to hold the new asset files.
NSString* tempDir = [self.assets_directory stringByAppendingPathComponent:@"TempAssetDir"];
NSError* error = nil;
#if NEW_LOCATION
id values[] = {[NSNumber numberWithUnsignedLong: kAssetDirectoryPermission]};
id keys[] = {NSFilePosixPermissions};
NSDictionary* attributes = [NSDictionary dictionaryWithObjects:values forKeys:keys count:1];
#else
struct passwd *user_info = getpwnam([kAssetDirectoryUser UTF8String]);
struct group *group_info = getgrnam([kAssetDirectoryGroup UTF8String]);
NSNumber* uid_num = [NSNumber numberWithUnsignedInt: user_info->pw_uid];
NSNumber* gid_num = [NSNumber numberWithUnsignedInt: group_info->gr_gid];
id values[] = {uid_num, gid_num, [NSNumber numberWithUnsignedLong: kAssetDirectoryPermission]};
id keys[] = {NSFileOwnerAccountID, NSFileGroupOwnerAccountID, NSFilePosixPermissions};
NSDictionary* attributes = [NSDictionary dictionaryWithObjects:values forKeys:keys count:3];
#endif
if (![self.fileManager createDirectoryAtPath:tempDir withIntermediateDirectories:YES
attributes:attributes error:&error])
{
OTAPKI_LOG("installAssetFiles: could not create directory return result;
}
#ifndef NEW_LOCATION
// Copy all of the asset files to the newly created directory
for (NSString* file_name in self.file_list)
{
NSString* download_assert_path = [assetDir stringByAppendingPathComponent:file_name];
NSString* asset_path = [tempDir stringByAppendingPathComponent:file_name];
if ([self.fileManager copyItemAtPath:download_assert_path toPath:asset_path error:&error])
{
chown([asset_path UTF8String], self.uid, self.gid);
}
else
{
[self.fileManager removeItemAtPath:tempDir error:nil];
return result;
}
}
#endif // !NEW_LOCATION
// Now that all of the files have been copied to the temp directory make a single call
// to rename (move) the temp directory to be the correct version directory. This rename
// allow for reducing a race conditions between this asset code and securityd.
NSInteger new_version_value = [self.next_asset_version integerValue];
NSString* new_version_dir_name = [NSString stringWithFormat:@" NSString* new_version_dir_path = [self.assets_directory stringByAppendingPathComponent:new_version_dir_name];
if (![self.fileManager moveItemAtPath:tempDir toPath:new_version_dir_path error:&error])
{
OTAPKI_LOG("installAssetFiles: could not move path [self.fileManager removeItemAtPath:tempDir error:nil];
return result;
}
result = YES;
return result;
}
/* --------------------------------------------------------------------------
OTAServiceApp getCurrentAssetDirectory:
Looks through the /var/Keychains/Assets directory to find latest asset
version directory. If no assets have been downloaded then nil is returned
and the current asset version is set to 0
-------------------------------------------------------------------------- */
- (NSString*)getCurrentAssetDirectory
{
NSString* result = nil;
BOOL isDir = NO;
OTAPKI_LOG("In getCurrentAssetDirectory\n");
OTAPKI_LOG("getCurrentAssetDirectory: checking to see if
// Check to see if the base directory is there
if (![self.fileManager fileExistsAtPath:(NSString *)kBaseAssetDirectoryPath isDirectory:&isDir] || !isDir)
{
OTAPKI_LOG("getCurrentAssetDirectory: // This might be fatal
return result;
}
NSError* error = nil;
NSInteger version_number = 0;
NSInteger current_version_number = 0;
int aVerNum = 0;
OSStatus err = noErr;
_assets_directory = [kBaseAssetDirectoryPath stringByAppendingPathComponent:(NSString *)kAssetDirectoryName];
OTAPKI_LOG("getCurrentAssetDirectory:
if ([self.fileManager fileExistsAtPath:self.assets_directory isDirectory:&isDir] && isDir)
{
OTAPKI_LOG("getCurrentAssetDirectory: NSDirectoryEnumerator* dirEnum = [self.fileManager enumeratorAtPath:self.assets_directory];
[dirEnum skipDescendents];
for (NSString* file in dirEnum)
{
if ([file hasPrefix:(NSString *)kVersionDirectoryNamePrefix])
{
NSString* version_str = [file substringFromIndex:[kVersionDirectoryNamePrefix length]];
NSInteger aVersion_number = [version_str integerValue];
if (aVersion_number > version_number)
{
version_number = aVersion_number;
}
}
}
}
else
{
#if NEW_LOCATION
id values[] = {[NSNumber numberWithUnsignedLong: kAssetDirectoryPermission]};
id keys[] = {NSFilePosixPermissions};
NSDictionary* attributes = [NSDictionary dictionaryWithObjects:values forKeys:keys count:1];
#else
struct passwd *user_info = getpwnam([kAssetDirectoryUser UTF8String]);
struct group *group_info = getgrnam([kAssetDirectoryGroup UTF8String]);
NSNumber* uid_num = [NSNumber numberWithUnsignedInt: user_info->pw_uid];
NSNumber* gid_num = [NSNumber numberWithUnsignedInt: group_info->gr_gid];
id values[] = {uid_num, gid_num, [NSNumber numberWithUnsignedLong: kAssetDirectoryPermission]};
id keys[] = {NSFileOwnerAccountID, NSFileGroupOwnerAccountID, NSFilePosixPermissions};
NSDictionary* attributes = [NSDictionary dictionaryWithObjects:values forKeys:keys count:3];
#endif
OTAPKI_LOG("getCurrentAssetDirectory: OTAPKI_LOG("getCurrentAssetDirectory: creating
if (![self.fileManager createDirectoryAtPath:self.assets_directory withIntermediateDirectories:YES
attributes:attributes error:&error])
{
OTAPKI_LOG("getCurrentAssetDirectory: failed to create return result;
}
}
err = SecTrustGetOTAPKIAssetVersionNumber(&aVerNum);
if (errSecSuccess == err && aVerNum > 0)
{
current_version_number = aVerNum;
}
if (version_number < current_version_number)
{
OTAPKI_LOG("The largest OTA version number is smaller than the current version number. This means the system has a newer asset\n");
version_number = current_version_number;
}
else
{
OTAPKI_LOG("The largest OTA version number is equal to the current version number. The OTA asset is newer than the system asset\n");
NSString* version_dir_name = [NSString stringWithFormat:@" result = [self.assets_directory stringByAppendingPathComponent:version_dir_name];
}
OTAPKI_LOG("getCurrentAssetDirectory: setting version number to _current_asset_version = [NSNumber numberWithInteger:version_number];
return result;
}
@end