2 * Copyright (c) 2003-2004,2006-2010,2013-2016 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 CFDataRef _CTWhiteListData
;
134 CFArrayRef _escrowCertificates
;
135 CFArrayRef _escrowPCSCertificates
;
136 CFDictionaryRef _evPolicyToAnchorMapping
;
137 CFDictionaryRef _anchorLookupTable
;
138 const char* _anchorTable
;
142 CFGiblisFor(SecOTAPKI
)
144 static CF_RETURNS_RETAINED CFStringRef
SecOTAPKICopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
)
146 SecOTAPKIRef otapkiRef
= (SecOTAPKIRef
)cf
;
147 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecOTAPKIRef: version %d>"), otapkiRef
->_assetVersion
);
150 static void SecOTAPKIDestroy(CFTypeRef cf
)
152 SecOTAPKIRef otapkiref
= (SecOTAPKIRef
)cf
;
154 CFReleaseNull(otapkiref
->_blackListSet
);
155 CFReleaseNull(otapkiref
->_grayListSet
);
156 CFReleaseNull(otapkiref
->_escrowCertificates
);
157 CFReleaseNull(otapkiref
->_escrowPCSCertificates
);
159 CFReleaseNull(otapkiref
->_evPolicyToAnchorMapping
);
160 CFReleaseNull(otapkiref
->_anchorLookupTable
);
162 free((void *)otapkiref
->_anchorTable
);
164 CFReleaseNull(otapkiref
->_trustedCTLogs
);
165 CFReleaseNull(otapkiref
->_CTWhiteListData
);
168 static CFDataRef
SecOTACopyFileContents(const char *path
)
170 CFMutableDataRef data
= NULL
;
171 int fd
= open(path
, O_RDONLY
, 0666);
178 off_t fsize
= lseek(fd
, 0, SEEK_END
);
179 if (fsize
== (off_t
)-1)
184 if (fsize
> (off_t
)INT32_MAX
)
189 data
= CFDataCreateMutable(kCFAllocatorDefault
, (CFIndex
)fsize
);
195 CFDataSetLength(data
, (CFIndex
)fsize
);
196 void *buf
= CFDataGetMutableBytePtr(data
);
202 off_t total_read
= 0;
203 while (total_read
< fsize
)
207 bytes_read
= pread(fd
, buf
, (size_t)(fsize
- total_read
), total_read
);
208 if (bytes_read
== -1)
216 total_read
+= bytes_read
;
236 static Boolean
PathExists(const char* path
, size_t* pFileSize
)
238 TestOTALog("In PathExists: checking path %s\n", path
);
239 Boolean result
= false;
242 if (NULL
!= pFileSize
)
247 int stat_result
= stat(path
, &sb
);
248 result
= (stat_result
== 0);
253 TestOTALog("In PathExists: stat returned 0 for %s\n", path
);
254 if (S_ISDIR(sb
.st_mode
))
256 TestOTALog("In PathExists: %s is a directory\n", path
);
262 TestOTALog("In PathExists: %s is a file\n", path
);
264 if (NULL
!= pFileSize
)
266 *pFileSize
= (size_t)sb
.st_size
;
273 TestOTALog("In PathExists: stat returned %d for %s\n", stat_result
, path
);
274 int local_errno
= errno
;
278 TestOTALog("In PathExists: stat failed because of EACCES\n");
282 TestOTALog("In PathExists: stat failed because of EBADF (Not likely)\n");
286 TestOTALog("In PathExists: stat failed because of EFAULT (huh?)\n");
290 TestOTALog("In PathExists: stat failed because of ELOOP (huh?)\n");
294 TestOTALog("In PathExists: stat failed because of ENAMETOOLONG (huh?)\n");
298 TestOTALog("In PathExists: stat failed because of ENOENT (missing?)\n");
302 TestOTALog("In PathExists: stat failed because of ENOMEM (really?)\n");
306 TestOTALog("In PathExists: stat failed because of ENOTDIR (really?)\n");
310 TestOTALog("In PathExists: stat failed because of EOVERFLOW (really?)\n");
314 TestOTALog("In PathExists: unknown errno of %d\n", local_errno
);
318 #endif // #if VERBOSE_LOGGING
323 static int unlink_cb(const char *fpath
, const struct stat
*sb
, int typeflag
, struct FTW
*ftwbuf
)
325 int rv
= remove(fpath
);
329 static int rmrf(char *path
)
331 const char* p1
= NULL
;
332 char path_buffer
[PATH_MAX
];
333 memset(path_buffer
, 0, sizeof(path_buffer
));
335 p1
= realpath(path
, path_buffer
);
336 if (!strncmp(path
, p1
, PATH_MAX
))
338 return nftw(path
, unlink_cb
, 64, FTW_DEPTH
| FTW_PHYS
);
344 static CFStringRef kSecSystemTrustStoreBundlePath
= CFSTR("/System/Library/Security/Certificates.bundle");
346 CFGiblisGetSingleton(CFBundleRef
, SecSystemTrustStoreGetBundle
, bundle
, ^{
347 CFStringRef bundlePath
= NULL
;
348 #if TARGET_IPHONE_SIMULATOR
349 char *simulatorRoot
= getenv("SIMULATOR_ROOT");
351 bundlePath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%s%@"), simulatorRoot
, kSecSystemTrustStoreBundlePath
);
354 bundlePath
= CFRetainSafe(kSecSystemTrustStoreBundlePath
);
355 TestOTAResourceLog("SecSystemTrustStoreGetBundle", bundlePath
, NULL
, NULL
, NULL
);
356 CFURLRef url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, bundlePath
, kCFURLPOSIXPathStyle
, true);
357 *bundle
= (url
) ? CFBundleCreate(kCFAllocatorDefault
, url
) : NULL
;
359 CFReleaseSafe(bundlePath
);
362 static CFURLRef
SecSystemTrustStoreCopyResourceURL(CFStringRef resourceName
,
363 CFStringRef resourceType
, CFStringRef subDirName
)
366 CFBundleRef bundle
= SecSystemTrustStoreGetBundle();
367 TestOTALog("SecSystemTrustStoreCopyResourceURL: bundle = %p\n", (void*)bundle
);
369 url
= CFBundleCopyResourceURL(bundle
, resourceName
,
370 resourceType
, subDirName
);
372 secwarning("resource: %@.%@ in %@ not found", resourceName
,
373 resourceType
, subDirName
);
377 TestOTAResourceLog("SecSystemTrustStoreCopyResourceURL: unable to get URL!",
378 resourceName
, resourceType
, subDirName
, url
);
380 TestOTAResourceLog("SecSystemTrustStoreCopyResourceURL: got URL from bundle",
381 resourceName
, resourceType
, subDirName
, url
);
386 static CFDataRef
SecSystemTrustStoreCopyResourceContents(CFStringRef resourceName
,
387 CFStringRef resourceType
, CFStringRef subDirName
)
389 CFURLRef url
= SecSystemTrustStoreCopyResourceURL(resourceName
, resourceType
, subDirName
);
390 CFDataRef data
= NULL
;
393 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
,
394 url
, &data
, NULL
, NULL
, &error
)) {
395 secwarning("read: %ld", (long) error
);
399 TestOTALog("SecSystemTrustStoreCopyResourceContents: data = %p\n", data
);
403 static CFPropertyListRef
CFPropertyListCopyFromAsset(const char *ota_assets_path
, CFStringRef asset
)
405 CFPropertyListRef plist
= NULL
;
406 // Check to see if the <asset>.plist file is in the asset location
407 CFDataRef xmlData
= NULL
;
408 if (ota_assets_path
) {
409 CFStringRef filePath
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s/%@.%@"), ota_assets_path
, asset
, CFSTR("plist"));
410 CFURLRef url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, filePath
, kCFURLPOSIXPathStyle
, false);
412 plist
= CFPropertyListReadFromFile(url
);
414 CFReleaseSafe(filePath
);
418 // no OTA asset file, so use the file in the system trust store bundle
419 xmlData
= SecSystemTrustStoreCopyResourceContents(asset
, CFSTR("plist"), NULL
);
422 plist
= CFPropertyListCreateWithData(kCFAllocatorDefault
, xmlData
, kCFPropertyListImmutable
, NULL
, NULL
);
430 static CFSetRef
CFSetCreateFromPropertyList(CFPropertyListRef plist
)
432 CFSetRef result
= NULL
;
435 CFMutableSetRef tempSet
= NULL
;
436 if (CFGetTypeID(plist
) == CFArrayGetTypeID()) {
437 tempSet
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
438 if (NULL
== tempSet
) {
441 CFArrayRef array
= (CFArrayRef
)plist
;
442 CFIndex num_keys
= CFArrayGetCount(array
);
443 for (CFIndex idx
= 0; idx
< num_keys
; idx
++) {
444 CFDataRef data
= (CFDataRef
)CFArrayGetValueAtIndex(array
, idx
);
445 CFSetAddValue(tempSet
, data
);
452 if (NULL
!= tempSet
) {
459 static const char* InitOTADirectory(int* pAssetVersion
)
461 TestOTALog("In InitOTADirectory\n");
462 const char* result
= NULL
;
464 char buffer
[PATH_MAX
];
468 int current_version
= 0;
469 int system_asset_version
= 0;
470 CFIndex asset_number
= 0;
472 // Look in the system trust store for an AssetVersion.plist file.
473 // This is needed to ensure that a software update did not put down
474 // a version of the trust store that is greater than the OTA assets.
476 CFDataRef assetVersionData
= SecSystemTrustStoreCopyResourceContents(CFSTR("AssetVersion"), CFSTR("plist"), NULL
);
477 if (NULL
!= assetVersionData
)
479 CFPropertyListFormat propFormat
;
480 CFDictionaryRef versionPlist
= CFPropertyListCreateWithData(kCFAllocatorDefault
, assetVersionData
, 0, &propFormat
, NULL
);
481 if (NULL
!= versionPlist
&& CFDictionaryGetTypeID() == CFGetTypeID(versionPlist
))
483 CFNumberRef versionNumber
= (CFNumberRef
)CFDictionaryGetValue(versionPlist
, (const void *)CFSTR("VersionNumber"));
484 if (NULL
!= versionNumber
)
486 CFNumberGetValue(versionNumber
, kCFNumberCFIndexType
, &asset_number
);
487 system_asset_version
= (int)asset_number
;
490 CFReleaseSafe(versionPlist
);
491 CFReleaseSafe(assetVersionData
);
494 // Now check to see if the OTA asset directory exists.
495 // If it does, get the greatest asset number in the OTA asset directory.
497 bool assetDirectoryExists
= PathExists(kBaseAssetDirectory
, NULL
);
498 if (assetDirectoryExists
)
500 TestOTALog("InitOTADirectory: %s exists\n", kBaseAssetDirectory
);
501 dp
= opendir (kBaseAssetDirectory
);
504 TestOTALog("InitOTADirectory: opendir sucessfully open %s\n", kBaseAssetDirectory
);
505 while ((ep
= readdir(dp
)))
507 TestOTALog("InitOTADirectory: processing name %s\n", ep
->d_name
);
508 if (strstr(ep
->d_name
, kVersionDirectoryNamePrefix
))
510 TestOTALog("InitOTADirectory: %s matches\n", ep
->d_name
);
511 memset(buffer
, 0, sizeof(buffer
));
512 snprintf(buffer
, sizeof(buffer
), "%s%s", kVersionDirectoryNamePrefix
, kNumberString
);
514 sscanf(ep
->d_name
, buffer
, &version
);
516 TestOTALog("InitOTADirectory: version = %d\n", version
);
518 if (current_version
> 0)
520 if (version
> current_version
)
522 // There is more than one Version_ directory.
523 // Delete the one with the smaller version number
524 memset(buffer
, 0, sizeof(buffer
));
525 snprintf(buffer
, sizeof(buffer
), "%s/%s%d", kBaseAssetDirectory
, kVersionDirectoryNamePrefix
, current_version
);
526 if (PathExists(buffer
, NULL
))
530 current_version
= version
;
535 current_version
= version
;
543 TestOTALog("InitOTADirectory: opendir failed to open %s\n", kBaseAssetDirectory
);
548 TestOTALog("InitOTADirectory: PathExists returned false for %s\n", kBaseAssetDirectory
);
551 // Check to see which version number is greater.
552 // If the current_version is greater then the OTA asset is newer.
553 // If the system_asset_version is greater than the system asset is newer.
554 if (current_version
> system_asset_version
)
556 // The OTA asset is newer than the system asset number
557 memset(buffer
, 0, sizeof(buffer
));
558 TestOTALog("InitOTADirectory: current_version = %d\n", current_version
);
559 snprintf(buffer
, sizeof(buffer
), "%s/%s%d", kBaseAssetDirectory
, kVersionDirectoryNamePrefix
, current_version
);
560 size_t length
= strlen(buffer
);
561 char* temp_str
= (char*)malloc(length
+ 1);
562 memset(temp_str
, 0, (length
+ 1));
563 strncpy(temp_str
, buffer
, length
);
568 // The system asset number is newer than the OTA asset number
569 current_version
= system_asset_version
;
572 free((void *)result
);
577 if (NULL
!= pAssetVersion
)
579 *pAssetVersion
= current_version
;
584 static CFSetRef
InitializeBlackList(const char* path_ptr
)
586 CFPropertyListRef plist
= CFPropertyListCopyFromAsset(path_ptr
, CFSTR("Blocked"));
587 CFSetRef result
= CFSetCreateFromPropertyList(plist
);
588 CFReleaseSafe(plist
);
593 static CFSetRef
InitializeGrayList(const char* path_ptr
)
595 CFPropertyListRef plist
= CFPropertyListCopyFromAsset(path_ptr
, CFSTR("GrayListedKeys"));
596 CFSetRef result
= CFSetCreateFromPropertyList(plist
);
597 CFReleaseSafe(plist
);
602 static CFDataRef
InitializeCTWhiteListData(const char* path_ptr
)
604 CFPropertyListRef data
= CFPropertyListCopyFromAsset(path_ptr
, CFSTR("CTWhiteListData"));
606 if (data
&& (CFGetTypeID(data
) == CFDataGetTypeID())) {
614 static CFDictionaryRef
InitializeAllowList(const char* path_ptr
)
616 CFPropertyListRef allowList
= CFPropertyListCopyFromAsset(path_ptr
, CFSTR("Allowed"));
618 if (allowList
&& (CFGetTypeID(allowList
) == CFDictionaryGetTypeID())) {
621 CFReleaseNull(allowList
);
626 static CFArrayRef
InitializeTrustedCTLogs(const char* path_ptr
)
628 CFPropertyListRef trustedCTLogs
= CFPropertyListCopyFromAsset(path_ptr
, CFSTR("TrustedCTLogs"));
630 if (trustedCTLogs
&& (CFGetTypeID(trustedCTLogs
) == CFArrayGetTypeID())) {
631 return trustedCTLogs
;
633 CFReleaseNull(trustedCTLogs
);
638 static CFDictionaryRef
InitializeEVPolicyToAnchorDigestsTable(const char* path_ptr
)
640 CFDictionaryRef result
= NULL
;
641 CFPropertyListRef evroots
= CFPropertyListCopyFromAsset(path_ptr
, CFSTR("EVRoots"));
644 if (CFGetTypeID(evroots
) == CFDictionaryGetTypeID()) {
645 /* @@@ Ensure that each dictionary key is a dotted list of digits,
646 each value is an NSArrayRef and each element in the array is a
648 result
= (CFDictionaryRef
)evroots
;
651 secwarning("EVRoot.plist is wrong type.");
659 static void* MapFile(const char* path
, int* out_fd
, size_t* out_file_size
)
662 void* temp_result
= NULL
;
663 if (NULL
== path
|| NULL
== out_fd
|| NULL
== out_file_size
)
672 *out_fd
= open(path
, O_RDONLY
, 0666);
679 off_t fsize
= lseek(*out_fd
, 0, SEEK_END
);
680 if (fsize
== (off_t
)-1)
685 if (fsize
> (off_t
)INT32_MAX
)
692 size_t malloc_size
= (size_t)fsize
;
694 temp_result
= malloc(malloc_size
);
695 if (NULL
== temp_result
)
702 *out_file_size
= malloc_size
;
704 off_t total_read
= 0;
705 while (total_read
< fsize
)
709 bytes_read
= pread(*out_fd
, temp_result
, (size_t)(fsize
- total_read
), total_read
);
710 if (bytes_read
== -1)
726 total_read
+= bytes_read
;
729 if (NULL
!= temp_result
)
731 result
= temp_result
;
737 static void UnMapFile(void* mapped_data
, size_t data_size
)
739 #pragma unused(mapped_data, data_size)
740 if (NULL
!= mapped_data
)
742 free((void *)mapped_data
);
747 static bool InitializeAnchorTable(const char* path_ptr
, CFDictionaryRef
* pLookupTable
, const char** ppAnchorTable
)
752 if (NULL
== pLookupTable
|| NULL
== ppAnchorTable
)
757 *pLookupTable
= NULL
;
758 *ppAnchorTable
= NULL
;;
760 const char* dir_path
= NULL
;
761 CFDataRef cert_index_file_data
= NULL
;
762 char file_path_buffer
[PATH_MAX
];
763 CFURLRef table_data_url
= NULL
;
764 CFStringRef table_data_cstr_path
= NULL
;
765 const char* table_data_path
= NULL
;
766 const index_record
* pIndex
= NULL
;
767 size_t index_offset
= 0;
768 size_t index_data_size
= 0;
769 CFMutableDictionaryRef anchorLookupTable
= NULL
;
770 uint32_t offset_int_value
= 0;
771 CFNumberRef index_offset_value
= NULL
;
772 CFDataRef index_hash
= NULL
;
773 CFMutableArrayRef offsets
= NULL
;
774 Boolean release_offset
= false;
776 char* local_anchorTable
= NULL
;
777 size_t local_anchorTableSize
= 0;
778 int local_anchorTable_fd
= -1;
780 // ------------------------------------------------------------------------
781 // First determine if there are asset files at /var/Keychains. If there
782 // are files use them for the trust table. Otherwise, use the files in the
783 // Security.framework bundle.
785 // The anchor table file is mapped into memory. This SHOULD be OK as the
786 // size of the data is around 250K.
787 // ------------------------------------------------------------------------
790 if (NULL
!= dir_path
)
792 // There is a set of OTA asset files
793 memset(file_path_buffer
, 0, PATH_MAX
);
794 snprintf(file_path_buffer
, PATH_MAX
, "%s/certsIndex.data", dir_path
);
795 cert_index_file_data
= SecOTACopyFileContents(file_path_buffer
);
797 if (NULL
!= cert_index_file_data
)
799 memset(file_path_buffer
, 0, PATH_MAX
);
800 snprintf(file_path_buffer
, PATH_MAX
, "%s/certsTable.data", dir_path
);
801 local_anchorTable
= (char *)MapFile(file_path_buffer
, &local_anchorTable_fd
, &local_anchorTableSize
);
804 free((void *)dir_path
);
808 // Check to see if kAnchorTable was indeed set
809 if (NULL
== local_anchorTable
)
811 // local_anchorTable is still NULL so the asset in the system trust store bundle needs to be used.
812 CFReleaseSafe(cert_index_file_data
);
813 cert_index_file_data
= SecSystemTrustStoreCopyResourceContents(CFSTR("certsIndex"), CFSTR("data"), NULL
);
814 if (!cert_index_file_data
) {
815 secerror("could not find certsIndex");
817 table_data_url
= SecSystemTrustStoreCopyResourceURL(CFSTR("certsTable"), CFSTR("data"), NULL
);
818 if (!table_data_url
) {
819 secerror("could not find certsTable");
822 if (NULL
!= table_data_url
)
824 table_data_cstr_path
= CFURLCopyFileSystemPath(table_data_url
, kCFURLPOSIXPathStyle
);
825 if (NULL
!= table_data_cstr_path
)
827 memset(file_path_buffer
, 0, PATH_MAX
);
828 table_data_path
= CFStringGetCStringPtr(table_data_cstr_path
, kCFStringEncodingUTF8
);
829 if (NULL
== table_data_path
)
831 if (CFStringGetCString(table_data_cstr_path
, file_path_buffer
, PATH_MAX
, kCFStringEncodingUTF8
))
833 table_data_path
= file_path_buffer
;
836 local_anchorTable
= (char *)MapFile(table_data_path
, &local_anchorTable_fd
, &local_anchorTableSize
);
837 CFReleaseSafe(table_data_cstr_path
);
840 CFReleaseSafe(table_data_url
);
843 if (NULL
== local_anchorTable
|| NULL
== cert_index_file_data
)
846 if (NULL
!= local_anchorTable
)
848 UnMapFile(local_anchorTable
, local_anchorTableSize
);
849 local_anchorTable
= NULL
;
850 local_anchorTableSize
= 0;
852 CFReleaseSafe(cert_index_file_data
);
856 // ------------------------------------------------------------------------
857 // Now that the locations of the files are known and the table file has
858 // been mapped into memory, create a dictionary that maps the SHA1 hash of
859 // normalized issuer to the offset in the mapped anchor table file which
860 // contains a index_record to the correct certificate
861 // ------------------------------------------------------------------------
862 pIndex
= (const index_record
*)CFDataGetBytePtr(cert_index_file_data
);
863 index_data_size
= CFDataGetLength(cert_index_file_data
);
865 anchorLookupTable
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
866 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
868 for (index_offset
= index_data_size
; index_offset
> 0; index_offset
-= sizeof(index_record
), pIndex
++)
870 offset_int_value
= pIndex
->offset
;
872 index_offset_value
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &offset_int_value
);
873 index_hash
= CFDataCreate(kCFAllocatorDefault
, pIndex
->hash
, CC_SHA1_DIGEST_LENGTH
);
875 // see if the dictionary already has this key
876 release_offset
= false;
877 offsets
= (CFMutableArrayRef
)CFDictionaryGetValue(anchorLookupTable
, index_hash
);
880 offsets
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
881 release_offset
= true;
885 CFArrayAppendValue(offsets
, index_offset_value
);
887 // set the key value pair in the dictionary
888 CFDictionarySetValue(anchorLookupTable
, index_hash
, offsets
);
890 CFRelease(index_offset_value
);
891 CFRelease(index_hash
);
898 CFRelease(cert_index_file_data
);
900 if (NULL
!= anchorLookupTable
&& NULL
!= local_anchorTable
)
902 *pLookupTable
= anchorLookupTable
;
903 *ppAnchorTable
= local_anchorTable
;
908 CFReleaseSafe(anchorLookupTable
);
909 if (NULL
!= local_anchorTable
)
911 UnMapFile(local_anchorTable
, local_anchorTableSize
);
912 //munmap(kAnchorTable, local_anchorTableSize);
913 local_anchorTable
= NULL
;
914 local_anchorTableSize
= 0;
921 static void InitializeEscrowCertificates(const char* path_ptr
, CFArrayRef
*escrowRoots
, CFArrayRef
*escrowPCSRoots
)
923 CFDataRef file_data
= NULL
;
925 const char* dir_path
= path_ptr
;
926 if (NULL
== dir_path
)
928 file_data
= SecSystemTrustStoreCopyResourceContents(CFSTR("AppleESCertificates"), CFSTR("plist"), NULL
);
933 memset(buffer
, 0, 1024);
934 snprintf(buffer
, 1024, "%s/AppleESCertificates.plist", dir_path
);
935 file_data
= SecOTACopyFileContents(buffer
);
938 if (NULL
!= file_data
)
940 CFPropertyListFormat propFormat
;
941 CFDictionaryRef certsDictionary
= CFPropertyListCreateWithData(kCFAllocatorDefault
, file_data
, 0, &propFormat
, NULL
);
942 if (NULL
!= certsDictionary
&& CFDictionaryGetTypeID() == CFGetTypeID((CFTypeRef
)certsDictionary
))
944 CFArrayRef certs
= (CFArrayRef
)CFDictionaryGetValue(certsDictionary
, CFSTR("ProductionEscrowKey"));
945 if (NULL
!= certs
&& CFArrayGetTypeID() == CFGetTypeID((CFTypeRef
)certs
) && CFArrayGetCount(certs
) > 0)
947 *escrowRoots
= CFArrayCreateCopy(kCFAllocatorDefault
, certs
);
949 CFArrayRef pcs_certs
= (CFArrayRef
)CFDictionaryGetValue(certsDictionary
, CFSTR("ProductionPCSEscrowKey"));
950 if (NULL
!= pcs_certs
&& CFArrayGetTypeID() == CFGetTypeID((CFTypeRef
)pcs_certs
) && CFArrayGetCount(pcs_certs
) > 0)
952 *escrowPCSRoots
= CFArrayCreateCopy(kCFAllocatorDefault
, pcs_certs
);
955 CFReleaseSafe(certsDictionary
);
956 CFRelease(file_data
);
962 static SecOTAPKIRef
SecOTACreate()
964 TestOTALog("In SecOTACreate\n");
966 SecOTAPKIRef otapkiref
= NULL
;
968 otapkiref
= CFTypeAllocate(SecOTAPKI
, struct _OpaqueSecOTAPKI
, kCFAllocatorDefault
);
970 if (NULL
== otapkiref
)
975 // Make sure that if this routine has to bail that the clean up
976 // will do the right thing
977 otapkiref
->_blackListSet
= NULL
;
978 otapkiref
->_grayListSet
= NULL
;
979 otapkiref
->_allowList
= NULL
;
980 otapkiref
->_trustedCTLogs
= NULL
;
981 otapkiref
->_CTWhiteListData
= NULL
;
982 otapkiref
->_escrowCertificates
= NULL
;
983 otapkiref
->_escrowPCSCertificates
= NULL
;
984 otapkiref
->_evPolicyToAnchorMapping
= NULL
;
985 otapkiref
->_anchorLookupTable
= NULL
;
986 otapkiref
->_anchorTable
= NULL
;
987 otapkiref
->_assetVersion
= 0;
989 // Start off by getting the correct asset directory info
990 int asset_version
= 0;
991 const char* path_ptr
= InitOTADirectory(&asset_version
);
992 otapkiref
->_assetVersion
= asset_version
;
994 TestOTALog("SecOTACreate: asset_path = %s\n", path_ptr
);
995 TestOTALog("SecOTACreate: asset_version = %d\n", asset_version
);
997 // Get the set of black listed keys
998 CFSetRef blackKeysSet
= InitializeBlackList(path_ptr
);
999 if (NULL
== blackKeysSet
)
1002 free((void *)path_ptr
);
1004 CFReleaseNull(otapkiref
);
1007 otapkiref
->_blackListSet
= blackKeysSet
;
1009 // Get the set of gray listed keys
1010 CFSetRef grayKeysSet
= InitializeGrayList(path_ptr
);
1011 if (NULL
== grayKeysSet
)
1014 free((void *)path_ptr
);
1016 CFReleaseNull(otapkiref
);
1019 otapkiref
->_grayListSet
= grayKeysSet
;
1021 // Get the allow list dictionary
1022 otapkiref
->_allowList
= InitializeAllowList(path_ptr
);
1024 // Get the trusted Certificate Transparency Logs
1025 otapkiref
->_trustedCTLogs
= InitializeTrustedCTLogs(path_ptr
);
1027 // Get the EV whitelist
1028 otapkiref
->_CTWhiteListData
= InitializeCTWhiteListData(path_ptr
);
1030 CFArrayRef escrowCerts
= NULL
;
1031 CFArrayRef escrowPCSCerts
= NULL
;
1032 InitializeEscrowCertificates(path_ptr
, &escrowCerts
, &escrowPCSCerts
);
1033 if (NULL
== escrowCerts
|| NULL
== escrowPCSCerts
)
1036 free((void *)path_ptr
);
1038 CFReleaseNull(escrowCerts
);
1039 CFReleaseNull(escrowPCSCerts
);
1040 CFReleaseNull(otapkiref
);
1043 otapkiref
->_escrowCertificates
= escrowCerts
;
1044 otapkiref
->_escrowPCSCertificates
= escrowPCSCerts
;
1046 // Get the mapping of EV Policy OIDs to Anchor digest
1047 CFDictionaryRef evOidToAnchorDigestMap
= InitializeEVPolicyToAnchorDigestsTable(path_ptr
);
1048 if (NULL
== evOidToAnchorDigestMap
)
1051 free((void *)path_ptr
);
1053 CFReleaseNull(otapkiref
);
1056 otapkiref
->_evPolicyToAnchorMapping
= evOidToAnchorDigestMap
;
1058 CFDictionaryRef anchorLookupTable
= NULL
;
1059 const char* anchorTablePtr
= NULL
;
1061 if (!InitializeAnchorTable(path_ptr
, &anchorLookupTable
, &anchorTablePtr
))
1063 CFReleaseSafe(anchorLookupTable
);
1064 if (anchorTablePtr
) {
1065 free((void *)anchorTablePtr
);
1068 free((void *)path_ptr
);
1070 CFReleaseNull(otapkiref
);
1073 otapkiref
->_anchorLookupTable
= anchorLookupTable
;
1074 otapkiref
->_anchorTable
= anchorTablePtr
;
1078 static dispatch_once_t kInitializeOTAPKI
= 0;
1079 static const char* kOTAQueueLabel
= "com.apple.security.OTAPKIQueue";
1080 static dispatch_queue_t kOTAQueue
;
1081 static SecOTAPKIRef kCurrentOTAPKIRef
= NULL
;
1083 SecOTAPKIRef
SecOTAPKICopyCurrentOTAPKIRef()
1085 __block SecOTAPKIRef result
= NULL
;
1086 dispatch_once(&kInitializeOTAPKI
,
1088 kOTAQueue
= dispatch_queue_create(kOTAQueueLabel
, NULL
);
1089 kCurrentOTAPKIRef
= SecOTACreate();
1092 dispatch_sync(kOTAQueue
,
1094 result
= kCurrentOTAPKIRef
;
1095 CFRetainSafe(result
);
1101 CFSetRef
SecOTAPKICopyBlackListSet(SecOTAPKIRef otapkiRef
)
1103 CFSetRef result
= NULL
;
1104 if (NULL
== otapkiRef
)
1109 result
= otapkiRef
->_blackListSet
;
1110 CFRetainSafe(result
);
1115 CFSetRef
SecOTAPKICopyGrayList(SecOTAPKIRef otapkiRef
)
1117 CFSetRef result
= NULL
;
1118 if (NULL
== otapkiRef
)
1123 result
= otapkiRef
->_grayListSet
;
1124 CFRetainSafe(result
);
1128 CFDictionaryRef
SecOTAPKICopyAllowList(SecOTAPKIRef otapkiRef
)
1130 CFDictionaryRef result
= NULL
;
1131 if (NULL
== otapkiRef
)
1136 result
= otapkiRef
->_allowList
;
1137 CFRetainSafe(result
);
1141 CFArrayRef
SecOTAPKICopyTrustedCTLogs(SecOTAPKIRef otapkiRef
)
1143 CFArrayRef result
= NULL
;
1144 if (NULL
== otapkiRef
)
1149 result
= otapkiRef
->_trustedCTLogs
;
1150 CFRetainSafe(result
);
1154 CFDataRef
SecOTAPKICopyCTWhiteList(SecOTAPKIRef otapkiRef
)
1156 CFDataRef result
= NULL
;
1157 if (NULL
== otapkiRef
)
1162 result
= otapkiRef
->_CTWhiteListData
;
1163 CFRetainSafe(result
);
1168 /* Returns an array of certificate data (CFDataRef) */
1169 CFArrayRef
SecOTAPKICopyEscrowCertificates(uint32_t escrowRootType
, SecOTAPKIRef otapkiRef
)
1171 CFMutableArrayRef result
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1172 if (NULL
== otapkiRef
) {
1176 switch (escrowRootType
) {
1177 // Note: we shouldn't be getting called to return baseline roots,
1178 // since this function vends production roots by definition.
1179 case kSecCertificateBaselineEscrowRoot
:
1180 case kSecCertificateProductionEscrowRoot
:
1181 case kSecCertificateBaselineEscrowBackupRoot
:
1182 case kSecCertificateProductionEscrowBackupRoot
:
1183 if (otapkiRef
->_escrowCertificates
) {
1184 CFArrayRef escrowCerts
= otapkiRef
->_escrowCertificates
;
1185 CFArrayAppendArray(result
, escrowCerts
, CFRangeMake(0, CFArrayGetCount(escrowCerts
)));
1188 case kSecCertificateBaselineEscrowEnrollmentRoot
:
1189 case kSecCertificateProductionEscrowEnrollmentRoot
:
1190 if (otapkiRef
->_escrowCertificates
) {
1191 // for enrollment purposes, exclude the v100 root
1192 static const unsigned char V100EscrowRoot
[] = {
1193 0x65,0x5C,0xB0,0x3C,0x39,0x3A,0x32,0xA6,0x0B,0x96,
1194 0x40,0xC0,0xCA,0x73,0x41,0xFD,0xC3,0x9E,0x96,0xB3
1196 CFArrayRef escrowCerts
= otapkiRef
->_escrowCertificates
;
1197 CFIndex idx
, count
= CFArrayGetCount(escrowCerts
);
1198 for (idx
=0; idx
< count
; idx
++) {
1199 CFDataRef tmpData
= (CFDataRef
) CFArrayGetValueAtIndex(escrowCerts
, idx
);
1200 SecCertificateRef tmpCert
= (tmpData
) ? SecCertificateCreateWithData(NULL
, tmpData
) : NULL
;
1201 CFDataRef sha1Hash
= (tmpCert
) ? SecCertificateGetSHA1Digest(tmpCert
) : NULL
;
1202 const uint8_t *dp
= (sha1Hash
) ? CFDataGetBytePtr(sha1Hash
) : NULL
;
1203 if (!(dp
&& !memcmp(V100EscrowRoot
, dp
, sizeof(V100EscrowRoot
))) && tmpData
) {
1204 CFArrayAppendValue(result
, tmpData
);
1206 CFReleaseSafe(tmpCert
);
1210 case kSecCertificateBaselinePCSEscrowRoot
:
1211 case kSecCertificateProductionPCSEscrowRoot
:
1212 if (otapkiRef
->_escrowPCSCertificates
) {
1213 CFArrayRef escrowPCSCerts
= otapkiRef
->_escrowPCSCertificates
;
1214 CFArrayAppendArray(result
, escrowPCSCerts
, CFRangeMake(0, CFArrayGetCount(escrowPCSCerts
)));
1225 CFDictionaryRef
SecOTAPKICopyEVPolicyToAnchorMapping(SecOTAPKIRef otapkiRef
)
1227 CFDictionaryRef result
= NULL
;
1228 if (NULL
== otapkiRef
)
1233 result
= otapkiRef
->_evPolicyToAnchorMapping
;
1234 CFRetainSafe(result
);
1239 CFDictionaryRef
SecOTAPKICopyAnchorLookupTable(SecOTAPKIRef otapkiRef
)
1241 CFDictionaryRef result
= NULL
;
1242 if (NULL
== otapkiRef
)
1247 result
= otapkiRef
->_anchorLookupTable
;
1248 CFRetainSafe(result
);
1252 const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef
)
1254 const char* result
= NULL
;
1255 if (NULL
== otapkiRef
)
1260 result
= otapkiRef
->_anchorTable
;
1264 int SecOTAPKIGetAssetVersion(SecOTAPKIRef otapkiRef
)
1267 if (NULL
== otapkiRef
)
1272 result
= otapkiRef
->_assetVersion
;
1276 void SecOTAPKIRefreshData()
1278 TestOTALog("In SecOTAPKIRefreshData\n");
1279 SecOTAPKIRef new_otaPKRef
= SecOTACreate();
1280 dispatch_sync(kOTAQueue
,
1282 CFReleaseSafe(kCurrentOTAPKIRef
);
1283 kCurrentOTAPKIRef
= new_otaPKRef
;
1287 /* Returns an array of certificate data (CFDataRef) */
1288 CFArrayRef
SecOTAPKICopyCurrentEscrowCertificates(uint32_t escrowRootType
, CFErrorRef
* error
)
1290 CFArrayRef result
= NULL
;
1292 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
1293 if (NULL
== otapkiref
)
1295 SecError(errSecInternal
, error
, CFSTR("Unable to get the current OTAPKIRef"));
1299 result
= SecOTAPKICopyEscrowCertificates(escrowRootType
, otapkiref
);
1300 CFRelease(otapkiref
);
1304 SecError(errSecInternal
, error
, CFSTR("Could not get escrow certificates from the current OTAPKIRef"));
1309 int SecOTAPKIGetCurrentAssetVersion(CFErrorRef
* error
)
1313 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
1314 if (NULL
== otapkiref
)
1316 SecError(errSecInternal
, error
, CFSTR("Unable to get the current OTAPKIRef"));
1320 result
= otapkiref
->_assetVersion
;
1324 int SecOTAPKISignalNewAsset(CFErrorRef
* error
)
1326 TestOTALog("SecOTAPKISignalNewAsset has been called!\n");
1327 SecOTAPKIRefreshData();