2 * Copyright (c) 2003-2004,2006-2010,2013-2014 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");
73 #define TestOTALog(sz, ...)
78 //#define NEW_LOCATION 1
81 static const char* kBaseAssertDirectory
= "/var/OTAPKI/Assets";
83 static const char* kBaseAssertDirectory
= "/var/Keychains/Assets";
86 static const char* kVersionDirectoryNamePrefix
= "Version_";
87 static const char* kNumberString
= "%d";
91 unsigned char hash
[CC_SHA1_DIGEST_LENGTH
];
94 typedef struct index_record index_record
;
97 struct _OpaqueSecOTAPKI
100 CFSetRef _blackListSet
;
101 CFSetRef _grayListSet
;
102 CFArrayRef _escrowCertificates
;
103 CFArrayRef _escrowPCSCertificates
;
104 CFDictionaryRef _evPolicyToAnchorMapping
;
105 CFDictionaryRef _anchorLookupTable
;
106 const char* _anchorTable
;
110 CFGiblisFor(SecOTAPKI
)
112 static CF_RETURNS_RETAINED CFStringRef
SecOTAPKICopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
)
114 SecOTAPKIRef otapkiRef
= (SecOTAPKIRef
)cf
;
115 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecOTAPKIRef: version %d>"), otapkiRef
->_assetVersion
);
118 static void SecOTAPKIDestroy(CFTypeRef cf
)
120 SecOTAPKIRef otapkiref
= (SecOTAPKIRef
)cf
;
122 CFReleaseNull(otapkiref
->_blackListSet
);
123 CFReleaseNull(otapkiref
->_grayListSet
);
124 CFReleaseNull(otapkiref
->_escrowCertificates
);
125 CFReleaseNull(otapkiref
->_escrowPCSCertificates
);
127 CFReleaseNull(otapkiref
->_evPolicyToAnchorMapping
);
128 CFReleaseNull(otapkiref
->_anchorLookupTable
);
130 free((void *)otapkiref
->_anchorTable
);
133 static CFDataRef
SecOTACopyFileContents(const char *path
)
135 CFMutableDataRef data
= NULL
;
136 int fd
= open(path
, O_RDONLY
, 0666);
143 off_t fsize
= lseek(fd
, 0, SEEK_END
);
144 if (fsize
== (off_t
)-1)
149 if (fsize
> (off_t
)INT32_MAX
)
154 data
= CFDataCreateMutable(kCFAllocatorDefault
, (CFIndex
)fsize
);
160 CFDataSetLength(data
, (CFIndex
)fsize
);
161 void *buf
= CFDataGetMutableBytePtr(data
);
167 off_t total_read
= 0;
168 while (total_read
< fsize
)
172 bytes_read
= pread(fd
, buf
, (size_t)(fsize
- total_read
), total_read
);
173 if (bytes_read
== -1)
181 total_read
+= bytes_read
;
201 static Boolean
PathExists(const char* path
, size_t* pFileSize
)
203 TestOTALog("In PathExists: checking path %s\n", path
);
204 Boolean result
= false;
207 if (NULL
!= pFileSize
)
212 int stat_result
= stat(path
, &sb
);
213 result
= (stat_result
== 0);
218 TestOTALog("In PathExists: stat returned 0 for %s\n", path
);
219 if (S_ISDIR(sb
.st_mode
))
221 TestOTALog("In PathExists: %s is a directory\n", path
);
227 TestOTALog("In PathExists: %s is a file\n", path
);
229 if (NULL
!= pFileSize
)
231 *pFileSize
= (size_t)sb
.st_size
;
238 TestOTALog("In PathExists: stat returned %d for %s\n", stat_result
, path
);
239 int local_errno
= errno
;
243 TestOTALog("In PathExists: stat failed because of EACCES\n");
247 TestOTALog("In PathExists: stat failed because of EBADF (Not likely)\n");
251 TestOTALog("In PathExists: stat failed because of EFAULT (huh?)\n");
255 TestOTALog("In PathExists: stat failed because of ELOOP (huh?)\n");
259 TestOTALog("In PathExists: stat failed because of ENAMETOOLONG (huh?)\n");
263 TestOTALog("In PathExists: stat failed because of ENOENT (missing?)\n");
267 TestOTALog("In PathExists: stat failed because of ENOMEM (really?)\n");
271 TestOTALog("In PathExists: stat failed because of ENOTDIR (really?)\n");
275 TestOTALog("In PathExists: stat failed because of EOVERFLOW (really?)\n");
279 TestOTALog("In PathExists: unknown errno of %d\n", local_errno
);
283 #endif // #if VERBOSE_LOGGING
288 static int unlink_cb(const char *fpath
, const struct stat
*sb
, int typeflag
, struct FTW
*ftwbuf
)
290 int rv
= remove(fpath
);
294 static int rmrf(char *path
)
296 const char* p1
= NULL
;
297 char path_buffer
[PATH_MAX
];
298 memset(path_buffer
, 0, sizeof(path_buffer
));
300 p1
= realpath(path
, path_buffer
);
301 if (!strncmp(path
, p1
, PATH_MAX
))
303 return nftw(path
, unlink_cb
, 64, FTW_DEPTH
| FTW_PHYS
);
308 static const char* InitOTADirectory(int* pAssetVersion
)
310 TestOTALog("In InitOTADirectory\n");
311 const char* result
= NULL
;
313 char buffer
[PATH_MAX
];
317 int current_version
= 0;
318 int system_asset_version
= 0;
319 CFIndex asset_number
= 0;
321 // Look in the resources for a AssetVerstion.plst file
322 // This is needed to be done to ensure that a software update did not put down a
323 // A version of the trust store that is greater than the OTA assets
324 CFDataRef assetVersionData
= SecFrameworkCopyResourceContents(CFSTR("AssetVersion"), CFSTR("plist"), NULL
);
325 if (NULL
!= assetVersionData
)
327 CFPropertyListFormat propFormat
;
328 CFDictionaryRef versionPlist
= CFPropertyListCreateWithData(kCFAllocatorDefault
, assetVersionData
, 0, &propFormat
, NULL
);
329 if (NULL
!= versionPlist
&& CFDictionaryGetTypeID() == CFGetTypeID(versionPlist
))
331 CFNumberRef versionNumber
= (CFNumberRef
)CFDictionaryGetValue(versionPlist
, (const void *)CFSTR("VersionNumber"));
332 if (NULL
!= versionNumber
)
334 CFNumberGetValue(versionNumber
, kCFNumberCFIndexType
, &asset_number
);
335 system_asset_version
= (int)asset_number
;
338 CFReleaseSafe(versionPlist
);
339 CFReleaseSafe(assetVersionData
);
342 // Now check to see if the OTA asset directory exists if it does then
343 // Get the greatest asset number in the OTA asset directory
344 bool assetDirectoryExists
= PathExists(kBaseAssertDirectory
, NULL
);
345 if (assetDirectoryExists
)
347 TestOTALog("InitOTADirectory: %s exists\n", kBaseAssertDirectory
);
348 dp
= opendir (kBaseAssertDirectory
);
351 TestOTALog("InitOTADirectory: opendir sucessfully open %s\n", kBaseAssertDirectory
);
352 while ((ep
= readdir(dp
)))
354 TestOTALog("InitOTADirectory: processing name %s\n", ep
->d_name
);
355 if (strstr(ep
->d_name
, kVersionDirectoryNamePrefix
))
357 TestOTALog("InitOTADirectory: %s matches\n", ep
->d_name
);
358 memset(buffer
, 0, sizeof(buffer
));
359 snprintf(buffer
, sizeof(buffer
), "%s%s", kVersionDirectoryNamePrefix
, kNumberString
);
361 sscanf(ep
->d_name
, buffer
, &version
);
363 TestOTALog("InitOTADirectory: version = %d\n", version
);
365 if (current_version
> 0)
367 if (version
> current_version
)
369 // There is more than one Version_ directory.
370 // Delete the one with the smaller version number
371 memset(buffer
, 0, sizeof(buffer
));
372 snprintf(buffer
, sizeof(buffer
), "%s/%s%d", kBaseAssertDirectory
, kVersionDirectoryNamePrefix
, current_version
);
373 if (PathExists(buffer
, NULL
))
377 current_version
= version
;
382 current_version
= version
;
390 TestOTALog("InitOTADirectory: opendir failed to open %s\n", kBaseAssertDirectory
);
395 TestOTALog("InitOTADirectory: PathExists returned false for %s\n", kBaseAssertDirectory
);
398 // Check to see which version number is greater.
399 // If the current_version is greater then the OTA asset is newer.
400 // If the system_asset_version is greater than the system asset is newer.
401 if (current_version
> system_asset_version
)
403 // The OTA asset is newer than the system asset number
404 memset(buffer
, 0, sizeof(buffer
));
405 TestOTALog("InitOTADirectory: current_version = %d\n", current_version
);
406 snprintf(buffer
, sizeof(buffer
), "%s/%s%d", kBaseAssertDirectory
, kVersionDirectoryNamePrefix
, current_version
);
407 size_t length
= strlen(buffer
);
408 char* temp_str
= (char*)malloc(length
+ 1);
409 memset(temp_str
, 0, (length
+ 1));
410 strncpy(temp_str
, buffer
, length
);
415 // The system asset number is newer than the OTA asset number
416 current_version
= system_asset_version
;
419 free((void *)result
);
424 if (NULL
!= pAssetVersion
)
426 *pAssetVersion
= current_version
;
431 static CFSetRef
InitializeBlackList(const char* path_ptr
)
433 CFSetRef result
= NULL
;
435 // Check to see if the EVRoots.plist file is in the asset location
436 CFDataRef xmlData
= NULL
;
437 const char* asset_path
= path_ptr
;
438 if (NULL
== asset_path
)
440 // There is no OTA asset file so use the file in the Sercurity.framework bundle
441 xmlData
= SecFrameworkCopyResourceContents(CFSTR("Blocked"), CFSTR("plist"), NULL
);
445 char file_path_buffer
[PATH_MAX
];
446 memset(file_path_buffer
, 0, PATH_MAX
);
447 snprintf(file_path_buffer
, PATH_MAX
, "%s/Blocked.plist", asset_path
);
449 xmlData
= SecOTACopyFileContents(file_path_buffer
);
453 xmlData
= SecFrameworkCopyResourceContents(CFSTR("Blocked"), CFSTR("plist"), NULL
);
457 CFPropertyListRef blackKeys
= NULL
;
460 blackKeys
= CFPropertyListCreateWithData(kCFAllocatorDefault
, xmlData
, kCFPropertyListImmutable
, NULL
, NULL
);
466 CFMutableSetRef tempSet
= NULL
;
467 if (CFGetTypeID(blackKeys
) == CFArrayGetTypeID())
469 tempSet
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
472 CFRelease(blackKeys
);
475 CFArrayRef blackKeyArray
= (CFArrayRef
)blackKeys
;
476 CFIndex num_keys
= CFArrayGetCount(blackKeyArray
);
477 for (CFIndex idx
= 0; idx
< num_keys
; idx
++)
479 CFDataRef key_data
= (CFDataRef
)CFArrayGetValueAtIndex(blackKeyArray
, idx
);
480 CFSetAddValue(tempSet
, key_data
);
485 CFRelease(blackKeys
);
493 CFRelease(blackKeys
);
499 static CFSetRef
InitializeGrayList(const char* path_ptr
)
501 CFSetRef result
= NULL
;
503 // Check to see if the EVRoots.plist file is in the asset location
504 CFDataRef xmlData
= NULL
;
505 const char* asset_path
= path_ptr
;
506 if (NULL
== asset_path
)
508 // There is no updated asset file so use the file in the Sercurity.framework bundle
509 xmlData
= SecFrameworkCopyResourceContents(CFSTR("GrayListedKeys"), CFSTR("plist"), NULL
);
513 char file_path_buffer
[PATH_MAX
];
514 memset(file_path_buffer
, 0, PATH_MAX
);
515 snprintf(file_path_buffer
, PATH_MAX
, "%s/GrayListedKeys.plist", asset_path
);
517 xmlData
= SecOTACopyFileContents(file_path_buffer
);
521 xmlData
= SecFrameworkCopyResourceContents(CFSTR("GrayListedKeys"), CFSTR("plist"), NULL
);
525 CFPropertyListRef grayKeys
= NULL
;
528 grayKeys
= CFPropertyListCreateWithData(kCFAllocatorDefault
, xmlData
, kCFPropertyListImmutable
, NULL
, NULL
);
534 CFMutableSetRef tempSet
= NULL
;
535 if (CFGetTypeID(grayKeys
) == CFArrayGetTypeID())
537 tempSet
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
543 CFArrayRef grayKeyArray
= (CFArrayRef
)grayKeys
;
544 CFIndex num_keys
= CFArrayGetCount(grayKeyArray
);
545 for (CFIndex idx
= 0; idx
< num_keys
; idx
++)
547 CFDataRef key_data
= (CFDataRef
)CFArrayGetValueAtIndex(grayKeyArray
, idx
);
548 CFSetAddValue(tempSet
, key_data
);
567 static CFDictionaryRef
InitializeEVPolicyToAnchorDigestsTable(const char* path_ptr
)
569 CFDictionaryRef result
= NULL
;
571 // Check to see if the EVRoots.plist file is in the asset location
572 CFDataRef xmlData
= NULL
;
573 const char* asset_path
= path_ptr
;
574 if (NULL
== asset_path
)
576 // There is no updated asset file so use the file in the Sercurity.framework bundle
577 xmlData
= SecFrameworkCopyResourceContents(CFSTR("EVRoots"), CFSTR("plist"), NULL
);
581 char file_path_buffer
[PATH_MAX
];
582 memset(file_path_buffer
, 0, PATH_MAX
);
583 snprintf(file_path_buffer
, PATH_MAX
, "%s/EVRoots.plist", asset_path
);
585 xmlData
= SecOTACopyFileContents(file_path_buffer
);
589 xmlData
= SecFrameworkCopyResourceContents(CFSTR("EVRoots"), CFSTR("plist"), NULL
);
593 CFPropertyListRef evroots
= NULL
;
596 evroots
= CFPropertyListCreateWithData(
597 kCFAllocatorDefault
, xmlData
, kCFPropertyListImmutable
, NULL
, NULL
);
603 if (CFGetTypeID(evroots
) == CFDictionaryGetTypeID())
605 /* @@@ Ensure that each dictionary key is a dotted list of digits,
606 each value is an NSArrayRef and each element in the array is a
609 result
= (CFDictionaryRef
)evroots
;
613 secwarning("EVRoot.plist is wrong type.");
621 static void* MapFile(const char* path
, int* out_fd
, size_t* out_file_size
)
624 void* temp_result
= NULL
;
625 if (NULL
== path
|| NULL
== out_fd
|| NULL
== out_file_size
)
634 *out_fd
= open(path
, O_RDONLY
, 0666);
641 off_t fsize
= lseek(*out_fd
, 0, SEEK_END
);
642 if (fsize
== (off_t
)-1)
647 if (fsize
> (off_t
)INT32_MAX
)
654 size_t malloc_size
= (size_t)fsize
;
656 temp_result
= malloc(malloc_size
);
657 if (NULL
== temp_result
)
664 *out_file_size
= malloc_size
;
666 off_t total_read
= 0;
667 while (total_read
< fsize
)
671 bytes_read
= pread(*out_fd
, temp_result
, (size_t)(fsize
- total_read
), total_read
);
672 if (bytes_read
== -1)
688 total_read
+= bytes_read
;
691 if (NULL
!= temp_result
)
693 result
= temp_result
;
699 static void UnMapFile(void* mapped_data
, size_t data_size
)
701 #pragma unused(mapped_data, data_size)
702 if (NULL
!= mapped_data
)
704 free((void *)mapped_data
);
709 static bool InitializeAnchorTable(const char* path_ptr
, CFDictionaryRef
* pLookupTable
, const char** ppAnchorTable
)
714 if (NULL
== pLookupTable
|| NULL
== ppAnchorTable
)
719 *pLookupTable
= NULL
;
720 *ppAnchorTable
= NULL
;;
722 // first see if there is a file at /var/db/OTA_Anchors
723 const char* dir_path
= NULL
;
724 CFDataRef cert_index_file_data
= NULL
;
725 char file_path_buffer
[PATH_MAX
];
726 CFURLRef table_data_url
= NULL
;
727 CFStringRef table_data_cstr_path
= NULL
;
728 const char* table_data_path
= NULL
;
729 const index_record
* pIndex
= NULL
;
730 size_t index_offset
= 0;
731 size_t index_data_size
= 0;
732 CFMutableDictionaryRef anchorLookupTable
= NULL
;
733 uint32_t offset_int_value
= 0;
734 CFNumberRef index_offset_value
= NULL
;
735 CFDataRef index_hash
= NULL
;
736 CFMutableArrayRef offsets
= NULL
;
737 Boolean release_offset
= false;
739 char* local_anchorTable
= NULL
;
740 size_t local_anchorTableSize
= 0;
741 int local_anchorTable_fd
= -1;
743 // ------------------------------------------------------------------------
744 // First determine if there are asset files at /var/Keychains. If there
745 // are files use them for the trust table. Otherwise, use the files in the
746 // Security.framework bundle.
748 // The anchor table file is mapped into memory. This SHOULD be OK as the
749 // size of the data is around 250K.
750 // ------------------------------------------------------------------------
753 if (NULL
!= dir_path
)
755 // There is a set of OTA asset files
756 memset(file_path_buffer
, 0, PATH_MAX
);
757 snprintf(file_path_buffer
, PATH_MAX
, "%s/certsIndex.data", dir_path
);
758 cert_index_file_data
= SecOTACopyFileContents(file_path_buffer
);
760 if (NULL
!= cert_index_file_data
)
762 memset(file_path_buffer
, 0, PATH_MAX
);
763 snprintf(file_path_buffer
, PATH_MAX
, "%s/certsTable.data", dir_path
);
764 local_anchorTable
= (char *)MapFile(file_path_buffer
, &local_anchorTable_fd
, &local_anchorTableSize
);
767 free((void *)dir_path
);
771 // Check to see if kAnchorTable was indeed set
772 if (NULL
== local_anchorTable
)
774 // local_anchorTable is still NULL so the asset in the Security framework needs to be used.
775 CFReleaseSafe(cert_index_file_data
);
776 cert_index_file_data
= SecFrameworkCopyResourceContents(CFSTR("certsIndex"), CFSTR("data"), NULL
);
777 table_data_url
= SecFrameworkCopyResourceURL(CFSTR("certsTable"), CFSTR("data"), NULL
);
778 if (NULL
!= table_data_url
)
780 table_data_cstr_path
= CFURLCopyFileSystemPath(table_data_url
, kCFURLPOSIXPathStyle
);
781 if (NULL
!= table_data_cstr_path
)
783 memset(file_path_buffer
, 0, PATH_MAX
);
784 table_data_path
= CFStringGetCStringPtr(table_data_cstr_path
, kCFStringEncodingUTF8
);
785 if (NULL
== table_data_path
)
787 if (CFStringGetCString(table_data_cstr_path
, file_path_buffer
, PATH_MAX
, kCFStringEncodingUTF8
))
789 table_data_path
= file_path_buffer
;
792 local_anchorTable
= (char *)MapFile(table_data_path
, &local_anchorTable_fd
, &local_anchorTableSize
);
793 CFReleaseSafe(table_data_cstr_path
);
796 CFReleaseSafe(table_data_url
);
799 if (NULL
== local_anchorTable
|| NULL
== cert_index_file_data
)
802 if (NULL
!= local_anchorTable
)
804 UnMapFile(local_anchorTable
, local_anchorTableSize
);
805 local_anchorTable
= NULL
;
806 local_anchorTableSize
= 0;
808 CFReleaseSafe(cert_index_file_data
);
812 // ------------------------------------------------------------------------
813 // Now that the locations of the files are known and the table file has
814 // been mapped into memory, create a dictionary that maps the SHA1 hash of
815 // normalized issuer to the offset in the mapped anchor table file which
816 // contains a index_record to the correct certificate
817 // ------------------------------------------------------------------------
818 pIndex
= (const index_record
*)CFDataGetBytePtr(cert_index_file_data
);
819 index_data_size
= CFDataGetLength(cert_index_file_data
);
821 anchorLookupTable
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
822 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
824 for (index_offset
= index_data_size
; index_offset
> 0; index_offset
-= sizeof(index_record
), pIndex
++)
826 offset_int_value
= pIndex
->offset
;
828 index_offset_value
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &offset_int_value
);
829 index_hash
= CFDataCreate(kCFAllocatorDefault
, pIndex
->hash
, CC_SHA1_DIGEST_LENGTH
);
831 // see if the dictionary already has this key
832 release_offset
= false;
833 offsets
= (CFMutableArrayRef
)CFDictionaryGetValue(anchorLookupTable
, index_hash
);
836 offsets
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
837 release_offset
= true;
841 CFArrayAppendValue(offsets
, index_offset_value
);
843 // set the key value pair in the dictionary
844 CFDictionarySetValue(anchorLookupTable
, index_hash
, offsets
);
846 CFRelease(index_offset_value
);
847 CFRelease(index_hash
);
854 CFRelease(cert_index_file_data
);
856 if (NULL
!= anchorLookupTable
&& NULL
!= local_anchorTable
)
858 *pLookupTable
= anchorLookupTable
;
859 *ppAnchorTable
= local_anchorTable
;
864 CFReleaseSafe(anchorLookupTable
);
865 if (NULL
!= local_anchorTable
)
867 UnMapFile(local_anchorTable
, local_anchorTableSize
);
868 //munmap(kAnchorTable, local_anchorTableSize);
869 local_anchorTable
= NULL
;
870 local_anchorTableSize
= 0;
877 static void InitializeEscrowCertificates(const char* path_ptr
, CFArrayRef
*escrowRoots
, CFArrayRef
*escrowPCSRoots
)
879 CFDataRef file_data
= NULL
;
881 const char* dir_path
= path_ptr
;
882 if (NULL
== dir_path
)
884 file_data
= SecFrameworkCopyResourceContents(CFSTR("AppleESCertificates"), CFSTR("plist"), NULL
);
889 memset(buffer
, 0, 1024);
890 snprintf(buffer
, 1024, "%s/AppleESCertificates.plist", dir_path
);
891 file_data
= SecOTACopyFileContents(buffer
);
894 if (NULL
!= file_data
)
896 CFPropertyListFormat propFormat
;
897 CFDictionaryRef certsDictionary
= CFPropertyListCreateWithData(kCFAllocatorDefault
, file_data
, 0, &propFormat
, NULL
);
898 if (NULL
!= certsDictionary
&& CFDictionaryGetTypeID() == CFGetTypeID((CFTypeRef
)certsDictionary
))
900 CFArrayRef certs
= (CFArrayRef
)CFDictionaryGetValue(certsDictionary
, CFSTR("ProductionEscrowKey"));
901 if (NULL
!= certs
&& CFArrayGetTypeID() == CFGetTypeID((CFTypeRef
)certs
) && CFArrayGetCount(certs
) > 0)
903 *escrowRoots
= CFArrayCreateCopy(kCFAllocatorDefault
, certs
);
905 CFArrayRef pcs_certs
= (CFArrayRef
)CFDictionaryGetValue(certsDictionary
, CFSTR("ProductionPCSEscrowKey"));
906 if (NULL
!= pcs_certs
&& CFArrayGetTypeID() == CFGetTypeID((CFTypeRef
)pcs_certs
) && CFArrayGetCount(pcs_certs
) > 0)
908 *escrowPCSRoots
= CFArrayCreateCopy(kCFAllocatorDefault
, pcs_certs
);
911 CFReleaseSafe(certsDictionary
);
912 CFRelease(file_data
);
918 static SecOTAPKIRef
SecOTACreate()
920 TestOTALog("In SecOTACreate\n");
922 SecOTAPKIRef otapkiref
= NULL
;
924 otapkiref
= CFTypeAllocate(SecOTAPKI
, struct _OpaqueSecOTAPKI
, kCFAllocatorDefault
);
926 if (NULL
== otapkiref
)
931 // Make sure that if this routine has to bail that the clean up
932 // will do the right thing
933 otapkiref
->_blackListSet
= NULL
;
934 otapkiref
->_grayListSet
= NULL
;
935 otapkiref
->_escrowCertificates
= NULL
;
936 otapkiref
->_escrowPCSCertificates
= NULL
;
937 otapkiref
->_evPolicyToAnchorMapping
= NULL
;
938 otapkiref
->_anchorLookupTable
= NULL
;
939 otapkiref
->_anchorTable
= NULL
;
940 otapkiref
->_assetVersion
= 0;
942 // Start off by getting the correct asset directory info
943 int asset_version
= 0;
944 const char* path_ptr
= InitOTADirectory(&asset_version
);
945 otapkiref
->_assetVersion
= asset_version
;
947 TestOTALog("SecOTACreate: asset_path = %s\n", path_ptr
);
948 TestOTALog("SecOTACreate: asset_version = %d\n", asset_version
);
950 // Get the set of black listed keys
951 CFSetRef blackKeysSet
= InitializeBlackList(path_ptr
);
952 if (NULL
== blackKeysSet
)
954 CFReleaseNull(otapkiref
);
957 otapkiref
->_blackListSet
= blackKeysSet
;
959 // Get the set of gray listed keys
960 CFSetRef grayKeysSet
= InitializeGrayList(path_ptr
);
961 if (NULL
== grayKeysSet
)
963 CFReleaseNull(otapkiref
);
966 otapkiref
->_grayListSet
= grayKeysSet
;
968 CFArrayRef escrowCerts
= NULL
;
969 CFArrayRef escrowPCSCerts
= NULL
;
970 InitializeEscrowCertificates(path_ptr
, &escrowCerts
, &escrowPCSCerts
);
971 if (NULL
== escrowCerts
|| NULL
== escrowPCSCerts
)
973 CFReleaseNull(escrowCerts
);
974 CFReleaseNull(escrowPCSCerts
);
975 CFReleaseNull(otapkiref
);
978 otapkiref
->_escrowCertificates
= escrowCerts
;
979 otapkiref
->_escrowPCSCertificates
= escrowPCSCerts
;
981 // Get the mapping of EV Policy OIDs to Anchor digest
982 CFDictionaryRef evOidToAnchorDigestMap
= InitializeEVPolicyToAnchorDigestsTable(path_ptr
);
983 if (NULL
== evOidToAnchorDigestMap
)
985 CFReleaseNull(otapkiref
);
988 otapkiref
->_evPolicyToAnchorMapping
= evOidToAnchorDigestMap
;
990 CFDictionaryRef anchorLookupTable
= NULL
;
991 const char* anchorTablePtr
= NULL
;
993 if (!InitializeAnchorTable(path_ptr
, &anchorLookupTable
, &anchorTablePtr
))
995 CFReleaseSafe(anchorLookupTable
);
996 if (NULL
!= anchorTablePtr
)
998 free((void *)anchorTablePtr
);
1001 CFReleaseNull(otapkiref
);
1004 otapkiref
->_anchorLookupTable
= anchorLookupTable
;
1005 otapkiref
->_anchorTable
= anchorTablePtr
;
1009 static dispatch_once_t kInitializeOTAPKI
= 0;
1010 static const char* kOTAQueueLabel
= "com.apple.security.OTAPKIQueue";
1011 static dispatch_queue_t kOTAQueue
;
1012 static SecOTAPKIRef kCurrentOTAPKIRef
= NULL
;
1014 SecOTAPKIRef
SecOTAPKICopyCurrentOTAPKIRef()
1016 __block SecOTAPKIRef result
= NULL
;
1017 dispatch_once(&kInitializeOTAPKI
,
1019 kOTAQueue
= dispatch_queue_create(kOTAQueueLabel
, NULL
);
1020 kCurrentOTAPKIRef
= SecOTACreate();
1023 dispatch_sync(kOTAQueue
,
1025 result
= kCurrentOTAPKIRef
;
1026 CFRetainSafe(result
);
1032 CFSetRef
SecOTAPKICopyBlackListSet(SecOTAPKIRef otapkiRef
)
1034 CFSetRef result
= NULL
;
1035 if (NULL
== otapkiRef
)
1040 result
= otapkiRef
->_blackListSet
;
1041 CFRetainSafe(result
);
1046 CFSetRef
SecOTAPKICopyGrayList(SecOTAPKIRef otapkiRef
)
1048 CFSetRef result
= NULL
;
1049 if (NULL
== otapkiRef
)
1054 result
= otapkiRef
->_grayListSet
;
1055 CFRetainSafe(result
);
1059 CFArrayRef
SecOTAPKICopyEscrowCertificates(uint32_t escrowRootType
, SecOTAPKIRef otapkiRef
)
1061 CFArrayRef result
= NULL
;
1062 if (NULL
== otapkiRef
)
1067 switch (escrowRootType
) {
1068 // Note: we shouldn't be getting called to return baseline roots,
1069 // since this function vends production roots by definition.
1070 case kSecCertificateBaselineEscrowRoot
:
1071 case kSecCertificateProductionEscrowRoot
:
1072 result
= otapkiRef
->_escrowCertificates
;
1074 case kSecCertificateBaselinePCSEscrowRoot
:
1075 case kSecCertificateProductionPCSEscrowRoot
:
1076 result
= otapkiRef
->_escrowPCSCertificates
;
1082 CFRetainSafe(result
);
1087 CFDictionaryRef
SecOTAPKICopyEVPolicyToAnchorMapping(SecOTAPKIRef otapkiRef
)
1089 CFDictionaryRef result
= NULL
;
1090 if (NULL
== otapkiRef
)
1095 result
= otapkiRef
->_evPolicyToAnchorMapping
;
1096 CFRetainSafe(result
);
1101 CFDictionaryRef
SecOTAPKICopyAnchorLookupTable(SecOTAPKIRef otapkiRef
)
1103 CFDictionaryRef result
= NULL
;
1104 if (NULL
== otapkiRef
)
1109 result
= otapkiRef
->_anchorLookupTable
;
1110 CFRetainSafe(result
);
1114 const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef
)
1116 const char* result
= NULL
;
1117 if (NULL
== otapkiRef
)
1122 result
= otapkiRef
->_anchorTable
;
1126 int SecOTAPKIGetAssetVersion(SecOTAPKIRef otapkiRef
)
1129 if (NULL
== otapkiRef
)
1134 result
= otapkiRef
->_assetVersion
;
1138 void SecOTAPKIRefreshData()
1140 TestOTALog("In SecOTAPKIRefreshData\n");
1141 SecOTAPKIRef new_otaPKRef
= SecOTACreate();
1142 dispatch_sync(kOTAQueue
,
1144 CFReleaseSafe(kCurrentOTAPKIRef
);
1145 kCurrentOTAPKIRef
= new_otaPKRef
;
1149 CFArrayRef
SecOTAPKICopyCurrentEscrowCertificates(uint32_t escrowRootType
, CFErrorRef
* error
)
1151 CFArrayRef result
= NULL
;
1153 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
1154 if (NULL
== otapkiref
)
1156 SecError(errSecInternal
, error
, CFSTR("Unable to get the current OTAPKIRef"));
1160 result
= SecOTAPKICopyEscrowCertificates(escrowRootType
, otapkiref
);
1161 CFRelease(otapkiref
);
1165 SecError(errSecInternal
, error
, CFSTR("Could not get escrow certificates from the current OTAPKIRef"));
1170 int SecOTAPKIGetCurrentAssetVersion(CFErrorRef
* error
)
1174 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
1175 if (NULL
== otapkiref
)
1177 SecError(errSecInternal
, error
, CFSTR("Unable to get the current OTAPKIRef"));
1181 result
= otapkiref
->_assetVersion
;
1185 int SecOTAPKISignalNewAsset(CFErrorRef
* error
)
1187 TestOTALog("SecOTAPKISignalNewAsset has been called!\n");
1188 SecOTAPKIRefreshData();