2 * Copyright (c) 2003-2004,2006-2010,2013-2015 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 #include "OTATrustUtilities.h"
35 #include <sys/syslimits.h>
38 #include <CoreFoundation/CoreFoundation.h>
40 #include "SecFramework.h"
42 #include <sys/param.h>
44 #include <utilities/SecCFRelease.h>
45 #include <utilities/SecCFError.h>
46 #include <utilities/SecCFWrappers.h>
47 #include <Security/SecBasePriv.h>
48 #include <Security/SecCertificatePriv.h>
49 #include <Security/SecFramework.h>
50 #include <dispatch/dispatch.h>
51 #include <CommonCrypto/CommonDigest.h>
53 //#define VERBOSE_LOGGING 1
57 static void TestOTALog(const char* sz
, ...)
62 FILE* fp
= fopen("/tmp/secd_OTAUtil.log", "a");
71 static void TestOTAResourceLog(const char *msg
,
72 CFStringRef resourceName
,
73 CFStringRef resourceType
,
74 CFStringRef subDirName
,
77 CFStringRef tmpStr
= NULL
;
78 CFIndex maxLength
= 0;
81 tmpStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
82 CFSTR("%s (name=%@, type=%@, subdir=%@), url=%@"),
83 msg
, resourceName
, resourceType
, subDirName
, url
);
85 maxLength
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(tmpStr
), kCFStringEncodingUTF8
) + 1;
86 buf
= (char*) malloc(maxLength
);
88 TestOTALog("TestOTAResourceLog: failed to create string of length %ld\n", (long)maxLength
);
91 if (CFStringGetCString(tmpStr
, buf
, (CFIndex
)maxLength
, kCFStringEncodingUTF8
)) {
92 TestOTALog("%s\n", buf
);
96 CFReleaseSafe(tmpStr
);
101 #define TestOTALog(sz, ...)
102 #define TestOTAResourceLog(msg, resourceName, resourceType, subDirName, url)
107 //#define NEW_LOCATION 1
110 static const char* kBaseAssetDirectory
= "/var/OTAPKI/Assets";
112 static const char* kBaseAssetDirectory
= "/var/Keychains/Assets";
115 static const char* kVersionDirectoryNamePrefix
= "Version_";
116 static const char* kNumberString
= "%d";
120 unsigned char hash
[CC_SHA1_DIGEST_LENGTH
];
123 typedef struct index_record index_record
;
126 struct _OpaqueSecOTAPKI
129 CFSetRef _blackListSet
;
130 CFSetRef _grayListSet
;
131 CFDictionaryRef _allowList
;
132 CFArrayRef _trustedCTLogs
;
133 CFArrayRef _escrowCertificates
;
134 CFArrayRef _escrowPCSCertificates
;
135 CFDictionaryRef _evPolicyToAnchorMapping
;
136 CFDictionaryRef _anchorLookupTable
;
137 const char* _anchorTable
;
141 CFGiblisFor(SecOTAPKI
)
143 static CF_RETURNS_RETAINED CFStringRef
SecOTAPKICopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
)
145 SecOTAPKIRef otapkiRef
= (SecOTAPKIRef
)cf
;
146 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecOTAPKIRef: version %d>"), otapkiRef
->_assetVersion
);
149 static void SecOTAPKIDestroy(CFTypeRef cf
)
151 SecOTAPKIRef otapkiref
= (SecOTAPKIRef
)cf
;
153 CFReleaseNull(otapkiref
->_blackListSet
);
154 CFReleaseNull(otapkiref
->_grayListSet
);
155 CFReleaseNull(otapkiref
->_escrowCertificates
);
156 CFReleaseNull(otapkiref
->_escrowPCSCertificates
);
158 CFReleaseNull(otapkiref
->_evPolicyToAnchorMapping
);
159 CFReleaseNull(otapkiref
->_anchorLookupTable
);
161 free((void *)otapkiref
->_anchorTable
);
163 CFReleaseNull(otapkiref
->_trustedCTLogs
);
166 static CFDataRef
SecOTACopyFileContents(const char *path
)
168 CFMutableDataRef data
= NULL
;
169 int fd
= open(path
, O_RDONLY
, 0666);
176 off_t fsize
= lseek(fd
, 0, SEEK_END
);
177 if (fsize
== (off_t
)-1)
182 if (fsize
> (off_t
)INT32_MAX
)
187 data
= CFDataCreateMutable(kCFAllocatorDefault
, (CFIndex
)fsize
);
193 CFDataSetLength(data
, (CFIndex
)fsize
);
194 void *buf
= CFDataGetMutableBytePtr(data
);
200 off_t total_read
= 0;
201 while (total_read
< fsize
)
205 bytes_read
= pread(fd
, buf
, (size_t)(fsize
- total_read
), total_read
);
206 if (bytes_read
== -1)
214 total_read
+= bytes_read
;
234 static Boolean
PathExists(const char* path
, size_t* pFileSize
)
236 TestOTALog("In PathExists: checking path %s\n", path
);
237 Boolean result
= false;
240 if (NULL
!= pFileSize
)
245 int stat_result
= stat(path
, &sb
);
246 result
= (stat_result
== 0);
251 TestOTALog("In PathExists: stat returned 0 for %s\n", path
);
252 if (S_ISDIR(sb
.st_mode
))
254 TestOTALog("In PathExists: %s is a directory\n", path
);
260 TestOTALog("In PathExists: %s is a file\n", path
);
262 if (NULL
!= pFileSize
)
264 *pFileSize
= (size_t)sb
.st_size
;
271 TestOTALog("In PathExists: stat returned %d for %s\n", stat_result
, path
);
272 int local_errno
= errno
;
276 TestOTALog("In PathExists: stat failed because of EACCES\n");
280 TestOTALog("In PathExists: stat failed because of EBADF (Not likely)\n");
284 TestOTALog("In PathExists: stat failed because of EFAULT (huh?)\n");
288 TestOTALog("In PathExists: stat failed because of ELOOP (huh?)\n");
292 TestOTALog("In PathExists: stat failed because of ENAMETOOLONG (huh?)\n");
296 TestOTALog("In PathExists: stat failed because of ENOENT (missing?)\n");
300 TestOTALog("In PathExists: stat failed because of ENOMEM (really?)\n");
304 TestOTALog("In PathExists: stat failed because of ENOTDIR (really?)\n");
308 TestOTALog("In PathExists: stat failed because of EOVERFLOW (really?)\n");
312 TestOTALog("In PathExists: unknown errno of %d\n", local_errno
);
316 #endif // #if VERBOSE_LOGGING
321 static int unlink_cb(const char *fpath
, const struct stat
*sb
, int typeflag
, struct FTW
*ftwbuf
)
323 int rv
= remove(fpath
);
327 static int rmrf(char *path
)
329 const char* p1
= NULL
;
330 char path_buffer
[PATH_MAX
];
331 memset(path_buffer
, 0, sizeof(path_buffer
));
333 p1
= realpath(path
, path_buffer
);
334 if (!strncmp(path
, p1
, PATH_MAX
))
336 return nftw(path
, unlink_cb
, 64, FTW_DEPTH
| FTW_PHYS
);
342 static CFStringRef kSecSystemTrustStoreBundlePath
= CFSTR("/System/Library/Security/Certificates.bundle");
344 CFGiblisGetSingleton(CFBundleRef
, SecSystemTrustStoreGetBundle
, bundle
, ^{
345 CFStringRef bundlePath
= NULL
;
346 #if TARGET_IPHONE_SIMULATOR
347 char *simulatorRoot
= getenv("SIMULATOR_ROOT");
349 bundlePath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%s%@"), simulatorRoot
, kSecSystemTrustStoreBundlePath
);
352 bundlePath
= CFRetainSafe(kSecSystemTrustStoreBundlePath
);
353 TestOTAResourceLog("SecSystemTrustStoreGetBundle", bundlePath
, NULL
, NULL
, NULL
);
354 CFURLRef url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, bundlePath
, kCFURLPOSIXPathStyle
, true);
355 *bundle
= (url
) ? CFBundleCreate(kCFAllocatorDefault
, url
) : NULL
;
357 CFReleaseSafe(bundlePath
);
360 static CFURLRef
SecSystemTrustStoreCopyResourceURL(CFStringRef resourceName
,
361 CFStringRef resourceType
, CFStringRef subDirName
)
364 CFBundleRef bundle
= SecSystemTrustStoreGetBundle();
365 TestOTALog("SecSystemTrustStoreCopyResourceURL: bundle = %p\n", (void*)bundle
);
367 url
= CFBundleCopyResourceURL(bundle
, resourceName
,
368 resourceType
, subDirName
);
370 secwarning("resource: %@.%@ in %@ not found", resourceName
,
371 resourceType
, subDirName
);
375 TestOTAResourceLog("SecSystemTrustStoreCopyResourceURL: unable to get URL!",
376 resourceName
, resourceType
, subDirName
, url
);
378 TestOTAResourceLog("SecSystemTrustStoreCopyResourceURL: got URL from bundle",
379 resourceName
, resourceType
, subDirName
, url
);
384 static CFDataRef
SecSystemTrustStoreCopyResourceContents(CFStringRef resourceName
,
385 CFStringRef resourceType
, CFStringRef subDirName
)
387 CFURLRef url
= SecSystemTrustStoreCopyResourceURL(resourceName
, resourceType
, subDirName
);
388 CFDataRef data
= NULL
;
391 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
,
392 url
, &data
, NULL
, NULL
, &error
)) {
393 secwarning("read: %ld", (long) error
);
397 TestOTALog("SecSystemTrustStoreCopyResourceContents: data = %p\n", data
);
402 static const char* InitOTADirectory(int* pAssetVersion
)
404 TestOTALog("In InitOTADirectory\n");
405 const char* result
= NULL
;
407 char buffer
[PATH_MAX
];
411 int current_version
= 0;
412 int system_asset_version
= 0;
413 CFIndex asset_number
= 0;
415 // Look in the system trust store for an AssetVersion.plist file.
416 // This is needed to ensure that a software update did not put down
417 // a version of the trust store that is greater than the OTA assets.
419 CFDataRef assetVersionData
= SecSystemTrustStoreCopyResourceContents(CFSTR("AssetVersion"), CFSTR("plist"), NULL
);
420 if (NULL
!= assetVersionData
)
422 CFPropertyListFormat propFormat
;
423 CFDictionaryRef versionPlist
= CFPropertyListCreateWithData(kCFAllocatorDefault
, assetVersionData
, 0, &propFormat
, NULL
);
424 if (NULL
!= versionPlist
&& CFDictionaryGetTypeID() == CFGetTypeID(versionPlist
))
426 CFNumberRef versionNumber
= (CFNumberRef
)CFDictionaryGetValue(versionPlist
, (const void *)CFSTR("VersionNumber"));
427 if (NULL
!= versionNumber
)
429 CFNumberGetValue(versionNumber
, kCFNumberCFIndexType
, &asset_number
);
430 system_asset_version
= (int)asset_number
;
433 CFReleaseSafe(versionPlist
);
434 CFReleaseSafe(assetVersionData
);
437 // Now check to see if the OTA asset directory exists.
438 // If it does, get the greatest asset number in the OTA asset directory.
440 bool assetDirectoryExists
= PathExists(kBaseAssetDirectory
, NULL
);
441 if (assetDirectoryExists
)
443 TestOTALog("InitOTADirectory: %s exists\n", kBaseAssetDirectory
);
444 dp
= opendir (kBaseAssetDirectory
);
447 TestOTALog("InitOTADirectory: opendir sucessfully open %s\n", kBaseAssetDirectory
);
448 while ((ep
= readdir(dp
)))
450 TestOTALog("InitOTADirectory: processing name %s\n", ep
->d_name
);
451 if (strstr(ep
->d_name
, kVersionDirectoryNamePrefix
))
453 TestOTALog("InitOTADirectory: %s matches\n", ep
->d_name
);
454 memset(buffer
, 0, sizeof(buffer
));
455 snprintf(buffer
, sizeof(buffer
), "%s%s", kVersionDirectoryNamePrefix
, kNumberString
);
457 sscanf(ep
->d_name
, buffer
, &version
);
459 TestOTALog("InitOTADirectory: version = %d\n", version
);
461 if (current_version
> 0)
463 if (version
> current_version
)
465 // There is more than one Version_ directory.
466 // Delete the one with the smaller version number
467 memset(buffer
, 0, sizeof(buffer
));
468 snprintf(buffer
, sizeof(buffer
), "%s/%s%d", kBaseAssetDirectory
, kVersionDirectoryNamePrefix
, current_version
);
469 if (PathExists(buffer
, NULL
))
473 current_version
= version
;
478 current_version
= version
;
486 TestOTALog("InitOTADirectory: opendir failed to open %s\n", kBaseAssetDirectory
);
491 TestOTALog("InitOTADirectory: PathExists returned false for %s\n", kBaseAssetDirectory
);
494 // Check to see which version number is greater.
495 // If the current_version is greater then the OTA asset is newer.
496 // If the system_asset_version is greater than the system asset is newer.
497 if (current_version
> system_asset_version
)
499 // The OTA asset is newer than the system asset number
500 memset(buffer
, 0, sizeof(buffer
));
501 TestOTALog("InitOTADirectory: current_version = %d\n", current_version
);
502 snprintf(buffer
, sizeof(buffer
), "%s/%s%d", kBaseAssetDirectory
, kVersionDirectoryNamePrefix
, current_version
);
503 size_t length
= strlen(buffer
);
504 char* temp_str
= (char*)malloc(length
+ 1);
505 memset(temp_str
, 0, (length
+ 1));
506 strncpy(temp_str
, buffer
, length
);
511 // The system asset number is newer than the OTA asset number
512 current_version
= system_asset_version
;
515 free((void *)result
);
520 if (NULL
!= pAssetVersion
)
522 *pAssetVersion
= current_version
;
527 static CFSetRef
InitializeBlackList(const char* path_ptr
)
529 CFSetRef result
= NULL
;
531 // Check to see if the EVRoots.plist file is in the asset location
532 CFDataRef xmlData
= NULL
;
533 const char* asset_path
= path_ptr
;
535 char file_path_buffer
[PATH_MAX
];
536 memset(file_path_buffer
, 0, PATH_MAX
);
537 snprintf(file_path_buffer
, PATH_MAX
, "%s/Blocked.plist", asset_path
);
539 xmlData
= SecOTACopyFileContents(file_path_buffer
);
543 // no OTA asset file, so use the file in the system trust store bundle
544 xmlData
= SecSystemTrustStoreCopyResourceContents(CFSTR("Blocked"), CFSTR("plist"), NULL
);
547 CFPropertyListRef blackKeys
= NULL
;
549 blackKeys
= CFPropertyListCreateWithData(kCFAllocatorDefault
, xmlData
, kCFPropertyListImmutable
, NULL
, NULL
);
554 CFMutableSetRef tempSet
= NULL
;
555 if (CFGetTypeID(blackKeys
) == CFArrayGetTypeID()) {
556 tempSet
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
557 if (NULL
== tempSet
) {
558 CFRelease(blackKeys
);
561 CFArrayRef blackKeyArray
= (CFArrayRef
)blackKeys
;
562 CFIndex num_keys
= CFArrayGetCount(blackKeyArray
);
563 for (CFIndex idx
= 0; idx
< num_keys
; idx
++) {
564 CFDataRef key_data
= (CFDataRef
)CFArrayGetValueAtIndex(blackKeyArray
, idx
);
565 CFSetAddValue(tempSet
, key_data
);
569 CFRelease(blackKeys
);
573 if (NULL
!= tempSet
) {
576 CFRelease(blackKeys
);
582 static CFSetRef
InitializeGrayList(const char* path_ptr
)
584 CFSetRef result
= NULL
;
586 // Check to see if the EVRoots.plist file is in the asset location
587 CFDataRef xmlData
= NULL
;
588 const char* asset_path
= path_ptr
;
590 char file_path_buffer
[PATH_MAX
];
591 memset(file_path_buffer
, 0, PATH_MAX
);
592 snprintf(file_path_buffer
, PATH_MAX
, "%s/GrayListedKeys.plist", asset_path
);
594 xmlData
= SecOTACopyFileContents(file_path_buffer
);
598 // no OTA asset file, so use the file in the system trust store bundle
599 xmlData
= SecSystemTrustStoreCopyResourceContents(CFSTR("GrayListedKeys"), CFSTR("plist"), NULL
);
602 CFPropertyListRef grayKeys
= NULL
;
604 grayKeys
= CFPropertyListCreateWithData(kCFAllocatorDefault
, xmlData
, kCFPropertyListImmutable
, NULL
, NULL
);
609 CFMutableSetRef tempSet
= NULL
;
610 if (CFGetTypeID(grayKeys
) == CFArrayGetTypeID()) {
611 tempSet
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
612 if (NULL
== tempSet
) {
616 CFArrayRef grayKeyArray
= (CFArrayRef
)grayKeys
;
617 CFIndex num_keys
= CFArrayGetCount(grayKeyArray
);
618 for (CFIndex idx
= 0; idx
< num_keys
; idx
++) {
619 CFDataRef key_data
= (CFDataRef
)CFArrayGetValueAtIndex(grayKeyArray
, idx
);
620 CFSetAddValue(tempSet
, key_data
);
628 if (NULL
!= tempSet
) {
637 static CFDictionaryRef
InitializeAllowList(const char* path_ptr
)
639 // Check to see if the Allowed.plist file is in the asset location
640 CFDataRef xmlData
= NULL
;
641 const char* asset_path
= path_ptr
;
643 char file_path_buffer
[PATH_MAX
];
644 memset(file_path_buffer
, 0, PATH_MAX
);
645 snprintf(file_path_buffer
, PATH_MAX
, "%s/Allowed.plist", asset_path
);
647 xmlData
= SecOTACopyFileContents(file_path_buffer
);
651 // no OTA asset file, so use the file in the system trust store bundle
652 xmlData
= SecSystemTrustStoreCopyResourceContents(CFSTR("Allowed"), CFSTR("plist"), NULL
);
655 CFPropertyListRef allowList
= NULL
;
657 allowList
= CFPropertyListCreateWithData(kCFAllocatorDefault
, xmlData
, kCFPropertyListImmutable
, NULL
, NULL
);
661 if (allowList
&& (CFGetTypeID(allowList
) == CFDictionaryGetTypeID())) {
664 CFReleaseNull(allowList
);
669 static CFArrayRef
InitializeTrustedCTLogs(const char* path_ptr
)
671 // Check to see if the TrustedCTLogs.plist file is in the asset location
672 CFDataRef xmlData
= NULL
;
673 const char* asset_path
= path_ptr
;
675 char file_path_buffer
[PATH_MAX
];
676 memset(file_path_buffer
, 0, PATH_MAX
);
677 snprintf(file_path_buffer
, PATH_MAX
, "%s/TrustedCTLogs.plist", asset_path
);
679 xmlData
= SecOTACopyFileContents(file_path_buffer
);
683 // no OTA asset file, so use the file in the system trust store bundle
684 xmlData
= SecSystemTrustStoreCopyResourceContents(CFSTR("TrustedCTLogs"), CFSTR("plist"), NULL
);
687 CFPropertyListRef trustedCTLogs
= NULL
;
689 trustedCTLogs
= CFPropertyListCreateWithData(kCFAllocatorDefault
, xmlData
, kCFPropertyListImmutable
, NULL
, NULL
);
693 if (trustedCTLogs
&& (CFGetTypeID(trustedCTLogs
) == CFArrayGetTypeID())) {
694 return trustedCTLogs
;
696 CFReleaseNull(trustedCTLogs
);
702 static CFDictionaryRef
InitializeEVPolicyToAnchorDigestsTable(const char* path_ptr
)
704 CFDictionaryRef result
= NULL
;
706 // Check to see if the EVRoots.plist file is in the asset location
707 CFDataRef xmlData
= NULL
;
708 const char* asset_path
= path_ptr
;
711 char file_path_buffer
[PATH_MAX
];
712 memset(file_path_buffer
, 0, PATH_MAX
);
713 snprintf(file_path_buffer
, PATH_MAX
, "%s/EVRoots.plist", asset_path
);
715 xmlData
= SecOTACopyFileContents(file_path_buffer
);
719 // no OTA asset file, so use the file in the system trust store bundle
720 xmlData
= SecSystemTrustStoreCopyResourceContents(CFSTR("EVRoots"), CFSTR("plist"), NULL
);
723 CFPropertyListRef evroots
= NULL
;
725 evroots
= CFPropertyListCreateWithData(
726 kCFAllocatorDefault
, xmlData
, kCFPropertyListImmutable
, NULL
, NULL
);
731 if (CFGetTypeID(evroots
) == CFDictionaryGetTypeID()) {
732 /* @@@ Ensure that each dictionary key is a dotted list of digits,
733 each value is an NSArrayRef and each element in the array is a
735 result
= (CFDictionaryRef
)evroots
;
738 secwarning("EVRoot.plist is wrong type.");
746 static void* MapFile(const char* path
, int* out_fd
, size_t* out_file_size
)
749 void* temp_result
= NULL
;
750 if (NULL
== path
|| NULL
== out_fd
|| NULL
== out_file_size
)
759 *out_fd
= open(path
, O_RDONLY
, 0666);
766 off_t fsize
= lseek(*out_fd
, 0, SEEK_END
);
767 if (fsize
== (off_t
)-1)
772 if (fsize
> (off_t
)INT32_MAX
)
779 size_t malloc_size
= (size_t)fsize
;
781 temp_result
= malloc(malloc_size
);
782 if (NULL
== temp_result
)
789 *out_file_size
= malloc_size
;
791 off_t total_read
= 0;
792 while (total_read
< fsize
)
796 bytes_read
= pread(*out_fd
, temp_result
, (size_t)(fsize
- total_read
), total_read
);
797 if (bytes_read
== -1)
813 total_read
+= bytes_read
;
816 if (NULL
!= temp_result
)
818 result
= temp_result
;
824 static void UnMapFile(void* mapped_data
, size_t data_size
)
826 #pragma unused(mapped_data, data_size)
827 if (NULL
!= mapped_data
)
829 free((void *)mapped_data
);
834 static bool InitializeAnchorTable(const char* path_ptr
, CFDictionaryRef
* pLookupTable
, const char** ppAnchorTable
)
839 if (NULL
== pLookupTable
|| NULL
== ppAnchorTable
)
844 *pLookupTable
= NULL
;
845 *ppAnchorTable
= NULL
;;
847 const char* dir_path
= NULL
;
848 CFDataRef cert_index_file_data
= NULL
;
849 char file_path_buffer
[PATH_MAX
];
850 CFURLRef table_data_url
= NULL
;
851 CFStringRef table_data_cstr_path
= NULL
;
852 const char* table_data_path
= NULL
;
853 const index_record
* pIndex
= NULL
;
854 size_t index_offset
= 0;
855 size_t index_data_size
= 0;
856 CFMutableDictionaryRef anchorLookupTable
= NULL
;
857 uint32_t offset_int_value
= 0;
858 CFNumberRef index_offset_value
= NULL
;
859 CFDataRef index_hash
= NULL
;
860 CFMutableArrayRef offsets
= NULL
;
861 Boolean release_offset
= false;
863 char* local_anchorTable
= NULL
;
864 size_t local_anchorTableSize
= 0;
865 int local_anchorTable_fd
= -1;
867 // ------------------------------------------------------------------------
868 // First determine if there are asset files at /var/Keychains. If there
869 // are files use them for the trust table. Otherwise, use the files in the
870 // Security.framework bundle.
872 // The anchor table file is mapped into memory. This SHOULD be OK as the
873 // size of the data is around 250K.
874 // ------------------------------------------------------------------------
877 if (NULL
!= dir_path
)
879 // There is a set of OTA asset files
880 memset(file_path_buffer
, 0, PATH_MAX
);
881 snprintf(file_path_buffer
, PATH_MAX
, "%s/certsIndex.data", dir_path
);
882 cert_index_file_data
= SecOTACopyFileContents(file_path_buffer
);
884 if (NULL
!= cert_index_file_data
)
886 memset(file_path_buffer
, 0, PATH_MAX
);
887 snprintf(file_path_buffer
, PATH_MAX
, "%s/certsTable.data", dir_path
);
888 local_anchorTable
= (char *)MapFile(file_path_buffer
, &local_anchorTable_fd
, &local_anchorTableSize
);
891 free((void *)dir_path
);
895 // Check to see if kAnchorTable was indeed set
896 if (NULL
== local_anchorTable
)
898 // local_anchorTable is still NULL so the asset in the system trust store bundle needs to be used.
899 CFReleaseSafe(cert_index_file_data
);
900 cert_index_file_data
= SecSystemTrustStoreCopyResourceContents(CFSTR("certsIndex"), CFSTR("data"), NULL
);
901 if (!cert_index_file_data
) {
902 secerror("could not find certsIndex");
904 table_data_url
= SecSystemTrustStoreCopyResourceURL(CFSTR("certsTable"), CFSTR("data"), NULL
);
905 if (!table_data_url
) {
906 secerror("could not find certsTable");
909 if (NULL
!= table_data_url
)
911 table_data_cstr_path
= CFURLCopyFileSystemPath(table_data_url
, kCFURLPOSIXPathStyle
);
912 if (NULL
!= table_data_cstr_path
)
914 memset(file_path_buffer
, 0, PATH_MAX
);
915 table_data_path
= CFStringGetCStringPtr(table_data_cstr_path
, kCFStringEncodingUTF8
);
916 if (NULL
== table_data_path
)
918 if (CFStringGetCString(table_data_cstr_path
, file_path_buffer
, PATH_MAX
, kCFStringEncodingUTF8
))
920 table_data_path
= file_path_buffer
;
923 local_anchorTable
= (char *)MapFile(table_data_path
, &local_anchorTable_fd
, &local_anchorTableSize
);
924 CFReleaseSafe(table_data_cstr_path
);
927 CFReleaseSafe(table_data_url
);
930 if (NULL
== local_anchorTable
|| NULL
== cert_index_file_data
)
933 if (NULL
!= local_anchorTable
)
935 UnMapFile(local_anchorTable
, local_anchorTableSize
);
936 local_anchorTable
= NULL
;
937 local_anchorTableSize
= 0;
939 CFReleaseSafe(cert_index_file_data
);
943 // ------------------------------------------------------------------------
944 // Now that the locations of the files are known and the table file has
945 // been mapped into memory, create a dictionary that maps the SHA1 hash of
946 // normalized issuer to the offset in the mapped anchor table file which
947 // contains a index_record to the correct certificate
948 // ------------------------------------------------------------------------
949 pIndex
= (const index_record
*)CFDataGetBytePtr(cert_index_file_data
);
950 index_data_size
= CFDataGetLength(cert_index_file_data
);
952 anchorLookupTable
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
953 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
955 for (index_offset
= index_data_size
; index_offset
> 0; index_offset
-= sizeof(index_record
), pIndex
++)
957 offset_int_value
= pIndex
->offset
;
959 index_offset_value
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &offset_int_value
);
960 index_hash
= CFDataCreate(kCFAllocatorDefault
, pIndex
->hash
, CC_SHA1_DIGEST_LENGTH
);
962 // see if the dictionary already has this key
963 release_offset
= false;
964 offsets
= (CFMutableArrayRef
)CFDictionaryGetValue(anchorLookupTable
, index_hash
);
967 offsets
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
968 release_offset
= true;
972 CFArrayAppendValue(offsets
, index_offset_value
);
974 // set the key value pair in the dictionary
975 CFDictionarySetValue(anchorLookupTable
, index_hash
, offsets
);
977 CFRelease(index_offset_value
);
978 CFRelease(index_hash
);
985 CFRelease(cert_index_file_data
);
987 if (NULL
!= anchorLookupTable
&& NULL
!= local_anchorTable
)
989 *pLookupTable
= anchorLookupTable
;
990 *ppAnchorTable
= local_anchorTable
;
995 CFReleaseSafe(anchorLookupTable
);
996 if (NULL
!= local_anchorTable
)
998 UnMapFile(local_anchorTable
, local_anchorTableSize
);
999 //munmap(kAnchorTable, local_anchorTableSize);
1000 local_anchorTable
= NULL
;
1001 local_anchorTableSize
= 0;
1008 static void InitializeEscrowCertificates(const char* path_ptr
, CFArrayRef
*escrowRoots
, CFArrayRef
*escrowPCSRoots
)
1010 CFDataRef file_data
= NULL
;
1012 const char* dir_path
= path_ptr
;
1013 if (NULL
== dir_path
)
1015 file_data
= SecSystemTrustStoreCopyResourceContents(CFSTR("AppleESCertificates"), CFSTR("plist"), NULL
);
1020 memset(buffer
, 0, 1024);
1021 snprintf(buffer
, 1024, "%s/AppleESCertificates.plist", dir_path
);
1022 file_data
= SecOTACopyFileContents(buffer
);
1025 if (NULL
!= file_data
)
1027 CFPropertyListFormat propFormat
;
1028 CFDictionaryRef certsDictionary
= CFPropertyListCreateWithData(kCFAllocatorDefault
, file_data
, 0, &propFormat
, NULL
);
1029 if (NULL
!= certsDictionary
&& CFDictionaryGetTypeID() == CFGetTypeID((CFTypeRef
)certsDictionary
))
1031 CFArrayRef certs
= (CFArrayRef
)CFDictionaryGetValue(certsDictionary
, CFSTR("ProductionEscrowKey"));
1032 if (NULL
!= certs
&& CFArrayGetTypeID() == CFGetTypeID((CFTypeRef
)certs
) && CFArrayGetCount(certs
) > 0)
1034 *escrowRoots
= CFArrayCreateCopy(kCFAllocatorDefault
, certs
);
1036 CFArrayRef pcs_certs
= (CFArrayRef
)CFDictionaryGetValue(certsDictionary
, CFSTR("ProductionPCSEscrowKey"));
1037 if (NULL
!= pcs_certs
&& CFArrayGetTypeID() == CFGetTypeID((CFTypeRef
)pcs_certs
) && CFArrayGetCount(pcs_certs
) > 0)
1039 *escrowPCSRoots
= CFArrayCreateCopy(kCFAllocatorDefault
, pcs_certs
);
1042 CFReleaseSafe(certsDictionary
);
1043 CFRelease(file_data
);
1049 static SecOTAPKIRef
SecOTACreate()
1051 TestOTALog("In SecOTACreate\n");
1053 SecOTAPKIRef otapkiref
= NULL
;
1055 otapkiref
= CFTypeAllocate(SecOTAPKI
, struct _OpaqueSecOTAPKI
, kCFAllocatorDefault
);
1057 if (NULL
== otapkiref
)
1062 // Make sure that if this routine has to bail that the clean up
1063 // will do the right thing
1064 otapkiref
->_blackListSet
= NULL
;
1065 otapkiref
->_grayListSet
= NULL
;
1066 otapkiref
->_allowList
= NULL
;
1067 otapkiref
->_trustedCTLogs
= NULL
;
1068 otapkiref
->_escrowCertificates
= NULL
;
1069 otapkiref
->_escrowPCSCertificates
= NULL
;
1070 otapkiref
->_evPolicyToAnchorMapping
= NULL
;
1071 otapkiref
->_anchorLookupTable
= NULL
;
1072 otapkiref
->_anchorTable
= NULL
;
1073 otapkiref
->_assetVersion
= 0;
1075 // Start off by getting the correct asset directory info
1076 int asset_version
= 0;
1077 const char* path_ptr
= InitOTADirectory(&asset_version
);
1078 otapkiref
->_assetVersion
= asset_version
;
1080 TestOTALog("SecOTACreate: asset_path = %s\n", path_ptr
);
1081 TestOTALog("SecOTACreate: asset_version = %d\n", asset_version
);
1083 // Get the set of black listed keys
1084 CFSetRef blackKeysSet
= InitializeBlackList(path_ptr
);
1085 if (NULL
== blackKeysSet
)
1088 free((void *)path_ptr
);
1090 CFReleaseNull(otapkiref
);
1093 otapkiref
->_blackListSet
= blackKeysSet
;
1095 // Get the set of gray listed keys
1096 CFSetRef grayKeysSet
= InitializeGrayList(path_ptr
);
1097 if (NULL
== grayKeysSet
)
1100 free((void *)path_ptr
);
1102 CFReleaseNull(otapkiref
);
1105 otapkiref
->_grayListSet
= grayKeysSet
;
1107 // Get the allow list dictionary
1108 otapkiref
->_allowList
= InitializeAllowList(path_ptr
);
1110 // Get the trusted Certificate Transparency Logs
1111 otapkiref
->_trustedCTLogs
= InitializeTrustedCTLogs(path_ptr
);
1113 CFArrayRef escrowCerts
= NULL
;
1114 CFArrayRef escrowPCSCerts
= NULL
;
1115 InitializeEscrowCertificates(path_ptr
, &escrowCerts
, &escrowPCSCerts
);
1116 if (NULL
== escrowCerts
|| NULL
== escrowPCSCerts
)
1119 free((void *)path_ptr
);
1121 CFReleaseNull(escrowCerts
);
1122 CFReleaseNull(escrowPCSCerts
);
1123 CFReleaseNull(otapkiref
);
1126 otapkiref
->_escrowCertificates
= escrowCerts
;
1127 otapkiref
->_escrowPCSCertificates
= escrowPCSCerts
;
1129 // Get the mapping of EV Policy OIDs to Anchor digest
1130 CFDictionaryRef evOidToAnchorDigestMap
= InitializeEVPolicyToAnchorDigestsTable(path_ptr
);
1131 if (NULL
== evOidToAnchorDigestMap
)
1134 free((void *)path_ptr
);
1136 CFReleaseNull(otapkiref
);
1139 otapkiref
->_evPolicyToAnchorMapping
= evOidToAnchorDigestMap
;
1141 CFDictionaryRef anchorLookupTable
= NULL
;
1142 const char* anchorTablePtr
= NULL
;
1144 if (!InitializeAnchorTable(path_ptr
, &anchorLookupTable
, &anchorTablePtr
))
1146 CFReleaseSafe(anchorLookupTable
);
1147 if (anchorTablePtr
) {
1148 free((void *)anchorTablePtr
);
1151 free((void *)path_ptr
);
1153 CFReleaseNull(otapkiref
);
1156 otapkiref
->_anchorLookupTable
= anchorLookupTable
;
1157 otapkiref
->_anchorTable
= anchorTablePtr
;
1161 static dispatch_once_t kInitializeOTAPKI
= 0;
1162 static const char* kOTAQueueLabel
= "com.apple.security.OTAPKIQueue";
1163 static dispatch_queue_t kOTAQueue
;
1164 static SecOTAPKIRef kCurrentOTAPKIRef
= NULL
;
1166 SecOTAPKIRef
SecOTAPKICopyCurrentOTAPKIRef()
1168 __block SecOTAPKIRef result
= NULL
;
1169 dispatch_once(&kInitializeOTAPKI
,
1171 kOTAQueue
= dispatch_queue_create(kOTAQueueLabel
, NULL
);
1172 kCurrentOTAPKIRef
= SecOTACreate();
1175 dispatch_sync(kOTAQueue
,
1177 result
= kCurrentOTAPKIRef
;
1178 CFRetainSafe(result
);
1184 CFSetRef
SecOTAPKICopyBlackListSet(SecOTAPKIRef otapkiRef
)
1186 CFSetRef result
= NULL
;
1187 if (NULL
== otapkiRef
)
1192 result
= otapkiRef
->_blackListSet
;
1193 CFRetainSafe(result
);
1198 CFSetRef
SecOTAPKICopyGrayList(SecOTAPKIRef otapkiRef
)
1200 CFSetRef result
= NULL
;
1201 if (NULL
== otapkiRef
)
1206 result
= otapkiRef
->_grayListSet
;
1207 CFRetainSafe(result
);
1211 CFDictionaryRef
SecOTAPKICopyAllowList(SecOTAPKIRef otapkiRef
)
1213 CFDictionaryRef result
= NULL
;
1214 if (NULL
== otapkiRef
)
1219 result
= otapkiRef
->_allowList
;
1220 CFRetainSafe(result
);
1224 CFArrayRef
SecOTAPKICopyTrustedCTLogs(SecOTAPKIRef otapkiRef
)
1226 CFArrayRef result
= NULL
;
1227 if (NULL
== otapkiRef
)
1232 result
= otapkiRef
->_trustedCTLogs
;
1233 CFRetainSafe(result
);
1238 CFArrayRef
SecOTAPKICopyEscrowCertificates(uint32_t escrowRootType
, SecOTAPKIRef otapkiRef
)
1240 CFArrayRef result
= NULL
;
1241 if (NULL
== otapkiRef
)
1246 switch (escrowRootType
) {
1247 // Note: we shouldn't be getting called to return baseline roots,
1248 // since this function vends production roots by definition.
1249 case kSecCertificateBaselineEscrowRoot
:
1250 case kSecCertificateProductionEscrowRoot
:
1251 result
= otapkiRef
->_escrowCertificates
;
1253 case kSecCertificateBaselinePCSEscrowRoot
:
1254 case kSecCertificateProductionPCSEscrowRoot
:
1255 result
= otapkiRef
->_escrowPCSCertificates
;
1261 CFRetainSafe(result
);
1266 CFDictionaryRef
SecOTAPKICopyEVPolicyToAnchorMapping(SecOTAPKIRef otapkiRef
)
1268 CFDictionaryRef result
= NULL
;
1269 if (NULL
== otapkiRef
)
1274 result
= otapkiRef
->_evPolicyToAnchorMapping
;
1275 CFRetainSafe(result
);
1280 CFDictionaryRef
SecOTAPKICopyAnchorLookupTable(SecOTAPKIRef otapkiRef
)
1282 CFDictionaryRef result
= NULL
;
1283 if (NULL
== otapkiRef
)
1288 result
= otapkiRef
->_anchorLookupTable
;
1289 CFRetainSafe(result
);
1293 const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef
)
1295 const char* result
= NULL
;
1296 if (NULL
== otapkiRef
)
1301 result
= otapkiRef
->_anchorTable
;
1305 int SecOTAPKIGetAssetVersion(SecOTAPKIRef otapkiRef
)
1308 if (NULL
== otapkiRef
)
1313 result
= otapkiRef
->_assetVersion
;
1317 void SecOTAPKIRefreshData()
1319 TestOTALog("In SecOTAPKIRefreshData\n");
1320 SecOTAPKIRef new_otaPKRef
= SecOTACreate();
1321 dispatch_sync(kOTAQueue
,
1323 CFReleaseSafe(kCurrentOTAPKIRef
);
1324 kCurrentOTAPKIRef
= new_otaPKRef
;
1328 CFArrayRef
SecOTAPKICopyCurrentEscrowCertificates(uint32_t escrowRootType
, CFErrorRef
* error
)
1330 CFArrayRef result
= NULL
;
1332 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
1333 if (NULL
== otapkiref
)
1335 SecError(errSecInternal
, error
, CFSTR("Unable to get the current OTAPKIRef"));
1339 result
= SecOTAPKICopyEscrowCertificates(escrowRootType
, otapkiref
);
1340 CFRelease(otapkiref
);
1344 SecError(errSecInternal
, error
, CFSTR("Could not get escrow certificates from the current OTAPKIRef"));
1349 int SecOTAPKIGetCurrentAssetVersion(CFErrorRef
* error
)
1353 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
1354 if (NULL
== otapkiref
)
1356 SecError(errSecInternal
, error
, CFSTR("Unable to get the current OTAPKIRef"));
1360 result
= otapkiref
->_assetVersion
;
1364 int SecOTAPKISignalNewAsset(CFErrorRef
* error
)
1366 TestOTALog("SecOTAPKISignalNewAsset has been called!\n");
1367 SecOTAPKIRefreshData();