2 * Copyright (c) 2003-2004,2006-2010,2013-2017 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 _pinningList
;
134 CFArrayRef _escrowCertificates
;
135 CFArrayRef _escrowPCSCertificates
;
136 CFDictionaryRef _evPolicyToAnchorMapping
;
137 CFDictionaryRef _anchorLookupTable
;
138 const char* _anchorTable
;
139 const char* _assetPath
;
141 const char* _validUpdateSnapshot
;
142 const char* _validDatabaseSnapshot
;
143 CFIndex _validSnapshotVersion
;
144 CFIndex _validSnapshotFormat
;
147 CFGiblisFor(SecOTAPKI
)
149 static CF_RETURNS_RETAINED CFStringRef
SecOTAPKICopyFormatDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
)
151 SecOTAPKIRef otapkiRef
= (SecOTAPKIRef
)cf
;
152 return CFStringCreateWithFormat(kCFAllocatorDefault
,NULL
,CFSTR("<SecOTAPKIRef: version %d>"), otapkiRef
->_assetVersion
);
155 static void SecOTAPKIDestroy(CFTypeRef cf
)
157 SecOTAPKIRef otapkiref
= (SecOTAPKIRef
)cf
;
159 CFReleaseNull(otapkiref
->_blackListSet
);
160 CFReleaseNull(otapkiref
->_grayListSet
);
161 CFReleaseNull(otapkiref
->_escrowCertificates
);
162 CFReleaseNull(otapkiref
->_escrowPCSCertificates
);
164 CFReleaseNull(otapkiref
->_evPolicyToAnchorMapping
);
165 CFReleaseNull(otapkiref
->_anchorLookupTable
);
167 CFReleaseNull(otapkiref
->_trustedCTLogs
);
168 CFReleaseNull(otapkiref
->_pinningList
);
170 if (otapkiref
->_anchorTable
) {
171 free((void *)otapkiref
->_anchorTable
);
172 otapkiref
->_anchorTable
= NULL
;
174 if (otapkiref
->_assetPath
) {
175 free((void *)otapkiref
->_assetPath
);
176 otapkiref
->_assetPath
= NULL
;
178 if (otapkiref
->_validUpdateSnapshot
) {
179 free((void *)otapkiref
->_validUpdateSnapshot
);
180 otapkiref
->_validUpdateSnapshot
= NULL
;
182 if (otapkiref
->_validDatabaseSnapshot
) {
183 free((void *)otapkiref
->_validDatabaseSnapshot
);
184 otapkiref
->_validDatabaseSnapshot
= NULL
;
188 static CFDataRef
SecOTACopyFileContents(const char *path
)
190 CFMutableDataRef data
= NULL
;
191 int fd
= open(path
, O_RDONLY
, 0666);
198 off_t fsize
= lseek(fd
, 0, SEEK_END
);
199 if (fsize
== (off_t
)-1)
204 if (fsize
> (off_t
)INT32_MAX
)
209 data
= CFDataCreateMutable(kCFAllocatorDefault
, (CFIndex
)fsize
);
215 CFDataSetLength(data
, (CFIndex
)fsize
);
216 void *buf
= CFDataGetMutableBytePtr(data
);
222 off_t total_read
= 0;
223 while (total_read
< fsize
)
227 bytes_read
= pread(fd
, buf
, (size_t)(fsize
- total_read
), total_read
);
228 if (bytes_read
== -1)
236 total_read
+= bytes_read
;
256 static Boolean
PathExists(const char* path
, size_t* pFileSize
)
258 const char *checked_path
= (path
) ? path
: "";
259 TestOTALog("In PathExists: checking path \"%s\"\n", checked_path
);
260 Boolean result
= false;
263 if (NULL
!= pFileSize
)
268 int stat_result
= stat(checked_path
, &sb
);
269 result
= (stat_result
== 0);
274 TestOTALog("In PathExists: stat returned 0 for \"%s\"\n", checked_path
);
275 if (S_ISDIR(sb
.st_mode
))
277 TestOTALog("In PathExists: \"%s\" is a directory\n", checked_path
);
283 TestOTALog("In PathExists: \"%s\" is a file\n", checked_path
);
285 if (NULL
!= pFileSize
)
287 *pFileSize
= (size_t)sb
.st_size
;
294 const char *stat_prefix
= "In PathExists: stat error";
295 TestOTALog("%s %d for \"%s\"\n", stat_prefix
, stat_result
, checked_path
);
296 int local_errno
= errno
;
300 TestOTALog("%s EACCES\n", stat_prefix
);
304 TestOTALog("%s EBADF\n", stat_prefix
);
308 TestOTALog("%s EFAULT\n", stat_prefix
);
312 TestOTALog("%s ELOOP\n", stat_prefix
);
316 TestOTALog("%s ENAMETOOLONG\n", stat_prefix
);
320 TestOTALog("%s ENOENT (missing?)\n", stat_prefix
);
324 TestOTALog("%s ENOMEM\n", stat_prefix
);
328 TestOTALog("%s ENOTDIR\n", stat_prefix
);
332 TestOTALog("%s EOVERFLOW\n", stat_prefix
);
336 TestOTALog("%s %d\n", stat_prefix
, local_errno
);
340 #endif // #if VERBOSE_LOGGING
345 static int unlink_cb(const char *fpath
, const struct stat
*sb
, int typeflag
, struct FTW
*ftwbuf
)
347 int rv
= remove(fpath
);
351 static int rmrf(char *path
)
353 const char* p1
= NULL
;
354 char path_buffer
[PATH_MAX
];
355 memset(path_buffer
, 0, sizeof(path_buffer
));
357 p1
= realpath(path
, path_buffer
);
358 if (p1
&& !strncmp(path
, p1
, PATH_MAX
))
360 return nftw(path
, unlink_cb
, 64, FTW_DEPTH
| FTW_PHYS
);
366 static CFStringRef kSecSystemTrustStoreBundlePath
= CFSTR("/System/Library/Security/Certificates.bundle");
368 CFGiblisGetSingleton(CFBundleRef
, SecSystemTrustStoreGetBundle
, bundle
, ^{
369 CFStringRef bundlePath
= NULL
;
370 #if TARGET_IPHONE_SIMULATOR
371 char *simulatorRoot
= getenv("SIMULATOR_ROOT");
373 bundlePath
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%s%@"), simulatorRoot
, kSecSystemTrustStoreBundlePath
);
376 bundlePath
= CFRetainSafe(kSecSystemTrustStoreBundlePath
);
377 TestOTAResourceLog("SecSystemTrustStoreGetBundle", bundlePath
, NULL
, NULL
, NULL
);
378 CFURLRef url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, bundlePath
, kCFURLPOSIXPathStyle
, true);
379 *bundle
= (url
) ? CFBundleCreate(kCFAllocatorDefault
, url
) : NULL
;
381 CFReleaseSafe(bundlePath
);
384 static CFURLRef
SecSystemTrustStoreCopyResourceURL(CFStringRef resourceName
,
385 CFStringRef resourceType
, CFStringRef subDirName
)
388 CFBundleRef bundle
= SecSystemTrustStoreGetBundle();
389 TestOTALog("SecSystemTrustStoreCopyResourceURL: bundle = %p\n", (void*)bundle
);
391 url
= CFBundleCopyResourceURL(bundle
, resourceName
,
392 resourceType
, subDirName
);
394 secwarning("resource: %@.%@ in %@ not found", resourceName
,
395 resourceType
, subDirName
);
399 TestOTAResourceLog("SecSystemTrustStoreCopyResourceURL: unable to get URL!",
400 resourceName
, resourceType
, subDirName
, url
);
402 TestOTAResourceLog("SecSystemTrustStoreCopyResourceURL: got URL from bundle",
403 resourceName
, resourceType
, subDirName
, url
);
408 static CFDataRef
SecSystemTrustStoreCopyResourceContents(CFStringRef resourceName
,
409 CFStringRef resourceType
, CFStringRef subDirName
)
411 CFURLRef url
= SecSystemTrustStoreCopyResourceURL(resourceName
, resourceType
, subDirName
);
412 CFDataRef data
= NULL
;
415 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
,
416 url
, &data
, NULL
, NULL
, &error
)) {
417 secwarning("read: %ld", (long) error
);
421 TestOTALog("SecSystemTrustStoreCopyResourceContents: data = %p\n", data
);
425 static CFPropertyListRef
CFPropertyListCopyFromAsset(const char *ota_assets_path
, CFStringRef asset
)
427 CFPropertyListRef plist
= NULL
;
428 // Check to see if the <asset>.plist file is in the asset location
429 CFDataRef xmlData
= NULL
;
430 if (ota_assets_path
) {
431 CFStringRef filePath
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%s/%@.%@"), ota_assets_path
, asset
, CFSTR("plist"));
432 CFURLRef url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, filePath
, kCFURLPOSIXPathStyle
, false);
434 plist
= CFPropertyListReadFromFile(url
);
436 CFReleaseSafe(filePath
);
440 // no OTA asset file, so use the file in the system trust store bundle
441 xmlData
= SecSystemTrustStoreCopyResourceContents(asset
, CFSTR("plist"), NULL
);
444 plist
= CFPropertyListCreateWithData(kCFAllocatorDefault
, xmlData
, kCFPropertyListImmutable
, NULL
, NULL
);
452 static CFSetRef
CFSetCreateFromPropertyList(CFPropertyListRef plist
)
454 CFSetRef result
= NULL
;
457 CFMutableSetRef tempSet
= NULL
;
458 if (CFGetTypeID(plist
) == CFArrayGetTypeID()) {
459 tempSet
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
460 if (NULL
== tempSet
) {
463 CFArrayRef array
= (CFArrayRef
)plist
;
464 CFIndex num_keys
= CFArrayGetCount(array
);
465 for (CFIndex idx
= 0; idx
< num_keys
; idx
++) {
466 CFDataRef data
= (CFDataRef
)CFArrayGetValueAtIndex(array
, idx
);
467 CFSetAddValue(tempSet
, data
);
474 if (NULL
!= tempSet
) {
481 static const char* InitOTADirectory(int* pAssetVersion
)
483 TestOTALog("In InitOTADirectory\n");
484 const char* result
= NULL
;
486 char buffer
[PATH_MAX
];
490 int current_version
= 0;
491 int system_asset_version
= 0;
492 CFIndex asset_number
= 0;
494 // Look in the system trust store for an AssetVersion.plist file.
495 // This is needed to ensure that a software update did not put down
496 // a version of the trust store that is greater than the OTA assets.
498 CFDataRef assetVersionData
= SecSystemTrustStoreCopyResourceContents(CFSTR("AssetVersion"), CFSTR("plist"), NULL
);
499 if (NULL
!= assetVersionData
)
501 CFPropertyListFormat propFormat
;
502 CFDictionaryRef versionPlist
= CFPropertyListCreateWithData(kCFAllocatorDefault
, assetVersionData
, 0, &propFormat
, NULL
);
503 if (NULL
!= versionPlist
&& CFDictionaryGetTypeID() == CFGetTypeID(versionPlist
))
505 CFNumberRef versionNumber
= (CFNumberRef
)CFDictionaryGetValue(versionPlist
, (const void *)CFSTR("VersionNumber"));
506 if (NULL
!= versionNumber
)
508 CFNumberGetValue(versionNumber
, kCFNumberCFIndexType
, &asset_number
);
509 system_asset_version
= (int)asset_number
;
512 CFReleaseSafe(versionPlist
);
513 CFReleaseSafe(assetVersionData
);
516 // Now check to see if the OTA asset directory exists.
517 // If it does, get the greatest asset number in the OTA asset directory.
519 bool assetDirectoryExists
= PathExists(kBaseAssetDirectory
, NULL
);
520 if (assetDirectoryExists
)
522 TestOTALog("InitOTADirectory: \"%s\" exists\n", kBaseAssetDirectory
);
523 dp
= opendir (kBaseAssetDirectory
);
526 TestOTALog("InitOTADirectory: opendir sucessfully open \"%s\"\n", kBaseAssetDirectory
);
527 while ((ep
= readdir(dp
)))
529 TestOTALog("InitOTADirectory: processing name \"%s\"\n", ep
->d_name
);
530 if (strstr(ep
->d_name
, kVersionDirectoryNamePrefix
))
532 TestOTALog("InitOTADirectory: \"%s\" matches\n", ep
->d_name
);
533 memset(buffer
, 0, sizeof(buffer
));
534 snprintf(buffer
, sizeof(buffer
), "%s%s", kVersionDirectoryNamePrefix
, kNumberString
);
535 #pragma clang diagnostic push
536 #pragma clang diagnostic ignored "-Wformat-nonliteral"
537 sscanf(ep
->d_name
, buffer
, &version
);
538 #pragma clang diagnostic pop
540 TestOTALog("InitOTADirectory: version = %d\n", version
);
542 if (current_version
> 0)
544 if (version
> current_version
)
546 // There is more than one Version_ directory.
547 // Delete the one with the smaller version number
548 memset(buffer
, 0, sizeof(buffer
));
549 snprintf(buffer
, sizeof(buffer
), "%s/%s%d", kBaseAssetDirectory
, kVersionDirectoryNamePrefix
, current_version
);
550 if (PathExists(buffer
, NULL
))
554 current_version
= version
;
559 current_version
= version
;
567 TestOTALog("InitOTADirectory: opendir failed to open %s\n", kBaseAssetDirectory
);
572 TestOTALog("InitOTADirectory: PathExists returned false for %s\n", kBaseAssetDirectory
);
575 // Check to see which version number is greater.
576 // If the current_version is greater then the OTA asset is newer.
577 // If the system_asset_version is greater than the system asset is newer.
578 if (current_version
> system_asset_version
)
580 // The OTA asset is newer than the system asset number
581 memset(buffer
, 0, sizeof(buffer
));
582 TestOTALog("InitOTADirectory: current_version = %d\n", current_version
);
583 snprintf(buffer
, sizeof(buffer
), "%s/%s%d", kBaseAssetDirectory
, kVersionDirectoryNamePrefix
, current_version
);
584 size_t length
= strlen(buffer
);
585 char* temp_str
= (char*)malloc(length
+ 1);
586 memset(temp_str
, 0, (length
+ 1));
587 strncpy(temp_str
, buffer
, length
);
592 // The system asset number is newer than the OTA asset number
593 current_version
= system_asset_version
;
596 free((void *)result
);
601 if (NULL
!= pAssetVersion
)
603 *pAssetVersion
= current_version
;
608 static CF_RETURNS_RETAINED CFSetRef
InitializeBlackList(const char* path_ptr
)
610 CFPropertyListRef plist
= CFPropertyListCopyFromAsset(path_ptr
, CFSTR("Blocked"));
611 CFSetRef result
= CFSetCreateFromPropertyList(plist
);
612 CFReleaseSafe(plist
);
617 static CF_RETURNS_RETAINED CFSetRef
InitializeGrayList(const char* path_ptr
)
619 CFPropertyListRef plist
= CFPropertyListCopyFromAsset(path_ptr
, CFSTR("GrayListedKeys"));
620 CFSetRef result
= CFSetCreateFromPropertyList(plist
);
621 CFReleaseSafe(plist
);
626 static CF_RETURNS_RETAINED CFArrayRef
InitializePinningList(const char* path_ptr
)
628 CFPropertyListRef list
= CFPropertyListCopyFromAsset(path_ptr
, CFSTR("CertificatePinning"));
638 static CF_RETURNS_RETAINED CFDictionaryRef
InitializeAllowList(const char* path_ptr
)
640 CFPropertyListRef allowList
= CFPropertyListCopyFromAsset(path_ptr
, CFSTR("Allowed"));
642 if (allowList
&& (CFGetTypeID(allowList
) == CFDictionaryGetTypeID())) {
645 CFReleaseNull(allowList
);
650 static CF_RETURNS_RETAINED CFArrayRef
InitializeTrustedCTLogs(const char* path_ptr
)
652 CFPropertyListRef trustedCTLogs
= CFPropertyListCopyFromAsset(path_ptr
, CFSTR("TrustedCTLogs"));
654 if (trustedCTLogs
&& (CFGetTypeID(trustedCTLogs
) == CFArrayGetTypeID())) {
655 return trustedCTLogs
;
657 CFReleaseNull(trustedCTLogs
);
662 static CF_RETURNS_RETAINED CFDictionaryRef
InitializeEVPolicyToAnchorDigestsTable(const char* path_ptr
)
664 CFDictionaryRef result
= NULL
;
665 CFPropertyListRef evroots
= CFPropertyListCopyFromAsset(path_ptr
, CFSTR("EVRoots"));
668 if (CFGetTypeID(evroots
) == CFDictionaryGetTypeID()) {
669 /* @@@ Ensure that each dictionary key is a dotted list of digits,
670 each value is an NSArrayRef and each element in the array is a
672 result
= (CFDictionaryRef
)evroots
;
675 secwarning("EVRoot.plist is wrong type.");
683 static CFIndex
InitializeValidSnapshotVersion(CFIndex
*outFormat
)
685 CFIndex validVersion
= 0;
686 CFIndex validFormat
= 0;
687 CFDataRef validVersionData
= SecSystemTrustStoreCopyResourceContents(CFSTR("ValidUpdate"), CFSTR("plist"), NULL
);
688 if (NULL
!= validVersionData
)
690 CFPropertyListFormat propFormat
;
691 CFDictionaryRef versionPlist
= CFPropertyListCreateWithData(kCFAllocatorDefault
, validVersionData
, 0, &propFormat
, NULL
);
692 if (NULL
!= versionPlist
&& CFDictionaryGetTypeID() == CFGetTypeID(versionPlist
))
694 CFNumberRef versionNumber
= (CFNumberRef
)CFDictionaryGetValue(versionPlist
, (const void *)CFSTR("Version"));
695 if (NULL
!= versionNumber
)
697 CFNumberGetValue(versionNumber
, kCFNumberCFIndexType
, &validVersion
);
699 CFNumberRef formatNumber
= (CFNumberRef
)CFDictionaryGetValue(versionPlist
, (const void *)CFSTR("Format"));
700 if (NULL
!= formatNumber
)
702 CFNumberGetValue(formatNumber
, kCFNumberCFIndexType
, &validFormat
);
705 CFReleaseSafe(versionPlist
);
706 CFReleaseSafe(validVersionData
);
709 *outFormat
= validFormat
;
714 static const char* InitializeValidSnapshotData(CFStringRef filename_str
)
717 const char *base_error_str
= "could not get valid snapshot";
719 CFURLRef valid_url
= SecSystemTrustStoreCopyResourceURL(filename_str
, CFSTR("sqlite3"), NULL
);
720 if (NULL
== valid_url
) {
721 secerror("%s", base_error_str
);
723 CFStringRef valid_str
= CFURLCopyFileSystemPath(valid_url
, kCFURLPOSIXPathStyle
);
724 char file_path_buffer
[PATH_MAX
];
725 memset(file_path_buffer
, 0, PATH_MAX
);
726 if (NULL
== valid_str
) {
727 secerror("%s path", base_error_str
);
729 const char *valid_cstr
= CFStringGetCStringPtr(valid_str
, kCFStringEncodingUTF8
);
730 if (NULL
== valid_cstr
) {
731 if (CFStringGetCString(valid_str
, file_path_buffer
, PATH_MAX
, kCFStringEncodingUTF8
)) {
732 valid_cstr
= file_path_buffer
;
735 if (NULL
== valid_cstr
) {
736 secerror("%s path as UTF8 string", base_error_str
);
738 asprintf(&result
, "%s", valid_cstr
);
741 CFReleaseSafe(valid_str
);
743 CFReleaseSafe(valid_url
);
744 if (result
&& !PathExists(result
, NULL
)) {
748 return (const char*)result
;
751 static const char* InitializeValidUpdateSnapshot()
753 return InitializeValidSnapshotData(CFSTR("update-full"));
756 static const char* InitializeValidDatabaseSnapshot()
758 return InitializeValidSnapshotData(CFSTR("valid"));
761 static void* MapFile(const char* path
, int* out_fd
, size_t* out_file_size
)
764 void* temp_result
= NULL
;
765 if (NULL
== path
|| NULL
== out_fd
|| NULL
== out_file_size
)
774 *out_fd
= open(path
, O_RDONLY
, 0666);
781 off_t fsize
= lseek(*out_fd
, 0, SEEK_END
);
782 if (fsize
== (off_t
)-1)
787 if (fsize
> (off_t
)INT32_MAX
)
794 size_t malloc_size
= (size_t)fsize
;
796 temp_result
= malloc(malloc_size
);
797 if (NULL
== temp_result
)
804 *out_file_size
= malloc_size
;
806 off_t total_read
= 0;
807 while (total_read
< fsize
)
811 bytes_read
= pread(*out_fd
, temp_result
, (size_t)(fsize
- total_read
), total_read
);
812 if (bytes_read
== -1)
828 total_read
+= bytes_read
;
831 if (NULL
!= temp_result
)
833 result
= temp_result
;
839 static void UnMapFile(void* mapped_data
, size_t data_size
)
841 #pragma unused(mapped_data, data_size)
842 if (NULL
!= mapped_data
)
844 free((void *)mapped_data
);
849 static bool InitializeAnchorTable(const char* path_ptr
, CFDictionaryRef
* pLookupTable
, const char** ppAnchorTable
)
854 if (NULL
== pLookupTable
|| NULL
== ppAnchorTable
)
859 *pLookupTable
= NULL
;
860 *ppAnchorTable
= NULL
;;
862 const char* dir_path
= NULL
;
863 CFDataRef cert_index_file_data
= NULL
;
864 char file_path_buffer
[PATH_MAX
];
865 CFURLRef table_data_url
= NULL
;
866 CFStringRef table_data_cstr_path
= NULL
;
867 const char* table_data_path
= NULL
;
868 const index_record
* pIndex
= NULL
;
869 size_t index_offset
= 0;
870 size_t index_data_size
= 0;
871 CFMutableDictionaryRef anchorLookupTable
= NULL
;
872 uint32_t offset_int_value
= 0;
873 CFNumberRef index_offset_value
= NULL
;
874 CFDataRef index_hash
= NULL
;
875 CFMutableArrayRef offsets
= NULL
;
876 Boolean release_offset
= false;
878 char* local_anchorTable
= NULL
;
879 size_t local_anchorTableSize
= 0;
880 int local_anchorTable_fd
= -1;
882 // ------------------------------------------------------------------------
883 // First determine if there are asset files at /var/Keychains. If there
884 // are files use them for the trust table. Otherwise, use the files in the
885 // Security.framework bundle.
887 // The anchor table file is mapped into memory. This SHOULD be OK as the
888 // size of the data is around 250K.
889 // ------------------------------------------------------------------------
892 if (NULL
!= dir_path
)
894 // There is a set of OTA asset files
895 memset(file_path_buffer
, 0, PATH_MAX
);
896 snprintf(file_path_buffer
, PATH_MAX
, "%s/certsIndex.data", dir_path
);
897 cert_index_file_data
= SecOTACopyFileContents(file_path_buffer
);
899 if (NULL
!= cert_index_file_data
)
901 memset(file_path_buffer
, 0, PATH_MAX
);
902 snprintf(file_path_buffer
, PATH_MAX
, "%s/certsTable.data", dir_path
);
903 local_anchorTable
= (char *)MapFile(file_path_buffer
, &local_anchorTable_fd
, &local_anchorTableSize
);
906 free((void *)dir_path
);
910 // Check to see if kAnchorTable was indeed set
911 if (NULL
== local_anchorTable
)
913 // local_anchorTable is still NULL so the asset in the system trust store bundle needs to be used.
914 CFReleaseSafe(cert_index_file_data
);
915 cert_index_file_data
= SecSystemTrustStoreCopyResourceContents(CFSTR("certsIndex"), CFSTR("data"), NULL
);
916 if (!cert_index_file_data
) {
917 secerror("could not find certsIndex");
919 table_data_url
= SecSystemTrustStoreCopyResourceURL(CFSTR("certsTable"), CFSTR("data"), NULL
);
920 if (!table_data_url
) {
921 secerror("could not find certsTable");
924 if (NULL
!= table_data_url
)
926 table_data_cstr_path
= CFURLCopyFileSystemPath(table_data_url
, kCFURLPOSIXPathStyle
);
927 if (NULL
!= table_data_cstr_path
)
929 memset(file_path_buffer
, 0, PATH_MAX
);
930 table_data_path
= CFStringGetCStringPtr(table_data_cstr_path
, kCFStringEncodingUTF8
);
931 if (NULL
== table_data_path
)
933 if (CFStringGetCString(table_data_cstr_path
, file_path_buffer
, PATH_MAX
, kCFStringEncodingUTF8
))
935 table_data_path
= file_path_buffer
;
938 local_anchorTable
= (char *)MapFile(table_data_path
, &local_anchorTable_fd
, &local_anchorTableSize
);
939 CFReleaseSafe(table_data_cstr_path
);
942 CFReleaseSafe(table_data_url
);
945 if (NULL
== local_anchorTable
|| NULL
== cert_index_file_data
)
948 if (NULL
!= local_anchorTable
)
950 UnMapFile(local_anchorTable
, local_anchorTableSize
);
951 local_anchorTable
= NULL
;
952 local_anchorTableSize
= 0;
954 CFReleaseSafe(cert_index_file_data
);
958 // ------------------------------------------------------------------------
959 // Now that the locations of the files are known and the table file has
960 // been mapped into memory, create a dictionary that maps the SHA1 hash of
961 // normalized issuer to the offset in the mapped anchor table file which
962 // contains a index_record to the correct certificate
963 // ------------------------------------------------------------------------
964 pIndex
= (const index_record
*)CFDataGetBytePtr(cert_index_file_data
);
965 index_data_size
= CFDataGetLength(cert_index_file_data
);
967 anchorLookupTable
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
968 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
970 for (index_offset
= index_data_size
; index_offset
> 0; index_offset
-= sizeof(index_record
), pIndex
++)
972 offset_int_value
= pIndex
->offset
;
974 index_offset_value
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &offset_int_value
);
975 index_hash
= CFDataCreate(kCFAllocatorDefault
, pIndex
->hash
, CC_SHA1_DIGEST_LENGTH
);
977 // see if the dictionary already has this key
978 release_offset
= false;
979 offsets
= (CFMutableArrayRef
)CFDictionaryGetValue(anchorLookupTable
, index_hash
);
982 offsets
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
983 release_offset
= true;
987 CFArrayAppendValue(offsets
, index_offset_value
);
989 // set the key value pair in the dictionary
990 CFDictionarySetValue(anchorLookupTable
, index_hash
, offsets
);
992 CFRelease(index_offset_value
);
993 CFRelease(index_hash
);
1000 CFRelease(cert_index_file_data
);
1002 if (NULL
!= anchorLookupTable
&& NULL
!= local_anchorTable
)
1004 *pLookupTable
= anchorLookupTable
;
1005 *ppAnchorTable
= local_anchorTable
;
1010 CFReleaseSafe(anchorLookupTable
);
1011 if (NULL
!= local_anchorTable
)
1013 UnMapFile(local_anchorTable
, local_anchorTableSize
);
1014 //munmap(kAnchorTable, local_anchorTableSize);
1015 local_anchorTable
= NULL
;
1016 local_anchorTableSize
= 0;
1023 static void InitializeEscrowCertificates(const char* path_ptr
, CFArrayRef
*escrowRoots
, CFArrayRef
*escrowPCSRoots
)
1025 CFDataRef file_data
= NULL
;
1027 const char* dir_path
= path_ptr
;
1028 if (NULL
== dir_path
)
1030 file_data
= SecSystemTrustStoreCopyResourceContents(CFSTR("AppleESCertificates"), CFSTR("plist"), NULL
);
1035 memset(buffer
, 0, 1024);
1036 snprintf(buffer
, 1024, "%s/AppleESCertificates.plist", dir_path
);
1037 file_data
= SecOTACopyFileContents(buffer
);
1040 if (NULL
!= file_data
)
1042 CFPropertyListFormat propFormat
;
1043 CFDictionaryRef certsDictionary
= CFPropertyListCreateWithData(kCFAllocatorDefault
, file_data
, 0, &propFormat
, NULL
);
1044 if (NULL
!= certsDictionary
&& CFDictionaryGetTypeID() == CFGetTypeID((CFTypeRef
)certsDictionary
))
1046 CFArrayRef certs
= (CFArrayRef
)CFDictionaryGetValue(certsDictionary
, CFSTR("ProductionEscrowKey"));
1047 if (NULL
!= certs
&& CFArrayGetTypeID() == CFGetTypeID((CFTypeRef
)certs
) && CFArrayGetCount(certs
) > 0)
1049 *escrowRoots
= CFArrayCreateCopy(kCFAllocatorDefault
, certs
);
1051 CFArrayRef pcs_certs
= (CFArrayRef
)CFDictionaryGetValue(certsDictionary
, CFSTR("ProductionPCSEscrowKey"));
1052 if (NULL
!= pcs_certs
&& CFArrayGetTypeID() == CFGetTypeID((CFTypeRef
)pcs_certs
) && CFArrayGetCount(pcs_certs
) > 0)
1054 *escrowPCSRoots
= CFArrayCreateCopy(kCFAllocatorDefault
, pcs_certs
);
1057 CFReleaseSafe(certsDictionary
);
1058 CFRelease(file_data
);
1064 static SecOTAPKIRef
SecOTACreate()
1066 TestOTALog("In SecOTACreate\n");
1068 SecOTAPKIRef otapkiref
= NULL
;
1070 otapkiref
= CFTypeAllocate(SecOTAPKI
, struct _OpaqueSecOTAPKI
, kCFAllocatorDefault
);
1072 if (NULL
== otapkiref
)
1077 // Make sure that if this routine has to bail that the clean up
1078 // will do the right thing
1079 otapkiref
->_blackListSet
= NULL
;
1080 otapkiref
->_grayListSet
= NULL
;
1081 otapkiref
->_allowList
= NULL
;
1082 otapkiref
->_trustedCTLogs
= NULL
;
1083 otapkiref
->_pinningList
= NULL
;
1084 otapkiref
->_escrowCertificates
= NULL
;
1085 otapkiref
->_escrowPCSCertificates
= NULL
;
1086 otapkiref
->_evPolicyToAnchorMapping
= NULL
;
1087 otapkiref
->_anchorLookupTable
= NULL
;
1088 otapkiref
->_anchorTable
= NULL
;
1089 otapkiref
->_assetPath
= NULL
;
1090 otapkiref
->_assetVersion
= 0;
1091 otapkiref
->_validUpdateSnapshot
= NULL
;
1092 otapkiref
->_validDatabaseSnapshot
= NULL
;
1093 otapkiref
->_validSnapshotVersion
= 0;
1094 otapkiref
->_validSnapshotFormat
= 0;
1096 // Start off by getting the correct asset directory info
1097 int asset_version
= 0;
1098 const char* path_ptr
= InitOTADirectory(&asset_version
);
1099 otapkiref
->_assetPath
= path_ptr
;
1100 otapkiref
->_assetVersion
= asset_version
;
1102 TestOTALog("SecOTACreate: asset_path = \"%s\"\n", (path_ptr
) ? path_ptr
: "");
1103 TestOTALog("SecOTACreate: asset_version = %d\n", asset_version
);
1105 // Get the set of black listed keys
1106 CFSetRef blackKeysSet
= InitializeBlackList(path_ptr
);
1107 if (NULL
== blackKeysSet
)
1109 CFReleaseNull(otapkiref
);
1112 otapkiref
->_blackListSet
= blackKeysSet
;
1114 // Get the set of gray listed keys
1115 CFSetRef grayKeysSet
= InitializeGrayList(path_ptr
);
1116 if (NULL
== grayKeysSet
)
1118 CFReleaseNull(otapkiref
);
1121 otapkiref
->_grayListSet
= grayKeysSet
;
1123 // Get the allow list dictionary
1124 // (now loaded lazily in SecOTAPKICopyAllowList)
1126 // Get the trusted Certificate Transparency Logs
1127 otapkiref
->_trustedCTLogs
= InitializeTrustedCTLogs(path_ptr
);
1129 // Get the pinning list
1130 otapkiref
->_pinningList
= InitializePinningList(path_ptr
);
1132 // Get the valid update snapshot version and format
1133 CFIndex update_format
= 0;
1134 otapkiref
->_validSnapshotVersion
= InitializeValidSnapshotVersion(&update_format
);
1135 otapkiref
->_validSnapshotFormat
= update_format
;
1137 // Get the valid update snapshot path (if it exists, NULL otherwise)
1138 otapkiref
->_validUpdateSnapshot
= InitializeValidUpdateSnapshot();
1140 // Get the valid database snapshot path (if it exists, NULL otherwise)
1141 otapkiref
->_validDatabaseSnapshot
= InitializeValidDatabaseSnapshot();
1143 CFArrayRef escrowCerts
= NULL
;
1144 CFArrayRef escrowPCSCerts
= NULL
;
1145 InitializeEscrowCertificates(path_ptr
, &escrowCerts
, &escrowPCSCerts
);
1146 if (NULL
== escrowCerts
|| NULL
== escrowPCSCerts
)
1148 CFReleaseNull(escrowCerts
);
1149 CFReleaseNull(escrowPCSCerts
);
1150 CFReleaseNull(otapkiref
);
1153 otapkiref
->_escrowCertificates
= escrowCerts
;
1154 otapkiref
->_escrowPCSCertificates
= escrowPCSCerts
;
1156 // Get the mapping of EV Policy OIDs to Anchor digest
1157 CFDictionaryRef evOidToAnchorDigestMap
= InitializeEVPolicyToAnchorDigestsTable(path_ptr
);
1158 if (NULL
== evOidToAnchorDigestMap
)
1160 CFReleaseNull(otapkiref
);
1163 otapkiref
->_evPolicyToAnchorMapping
= evOidToAnchorDigestMap
;
1165 CFDictionaryRef anchorLookupTable
= NULL
;
1166 const char* anchorTablePtr
= NULL
;
1168 if (!InitializeAnchorTable(path_ptr
, &anchorLookupTable
, &anchorTablePtr
))
1170 CFReleaseSafe(anchorLookupTable
);
1171 if (anchorTablePtr
) {
1172 free((void *)anchorTablePtr
);
1174 CFReleaseNull(otapkiref
);
1177 otapkiref
->_anchorLookupTable
= anchorLookupTable
;
1178 otapkiref
->_anchorTable
= anchorTablePtr
;
1182 static dispatch_once_t kInitializeOTAPKI
= 0;
1183 static const char* kOTAQueueLabel
= "com.apple.security.OTAPKIQueue";
1184 static dispatch_queue_t kOTAQueue
;
1185 static SecOTAPKIRef kCurrentOTAPKIRef
= NULL
;
1187 SecOTAPKIRef
SecOTAPKICopyCurrentOTAPKIRef()
1189 __block SecOTAPKIRef result
= NULL
;
1190 dispatch_once(&kInitializeOTAPKI
,
1192 kOTAQueue
= dispatch_queue_create(kOTAQueueLabel
, NULL
);
1193 kCurrentOTAPKIRef
= SecOTACreate();
1196 dispatch_sync(kOTAQueue
,
1198 result
= kCurrentOTAPKIRef
;
1199 CFRetainSafe(result
);
1205 CFSetRef
SecOTAPKICopyBlackListSet(SecOTAPKIRef otapkiRef
)
1207 CFSetRef result
= NULL
;
1208 if (NULL
== otapkiRef
)
1213 result
= otapkiRef
->_blackListSet
;
1214 CFRetainSafe(result
);
1219 CFSetRef
SecOTAPKICopyGrayList(SecOTAPKIRef otapkiRef
)
1221 CFSetRef result
= NULL
;
1222 if (NULL
== otapkiRef
)
1227 result
= otapkiRef
->_grayListSet
;
1228 CFRetainSafe(result
);
1232 CFDictionaryRef
SecOTAPKICopyAllowList(SecOTAPKIRef otapkiRef
)
1234 CFDictionaryRef result
= NULL
;
1235 if (NULL
== otapkiRef
)
1240 result
= otapkiRef
->_allowList
;
1242 result
= InitializeAllowList(otapkiRef
->_assetPath
);
1243 otapkiRef
->_allowList
= result
;
1246 CFRetainSafe(result
);
1250 CFArrayRef
SecOTAPKICopyAllowListForAuthKeyID(SecOTAPKIRef otapkiRef
, CFStringRef authKeyID
)
1252 // %%% temporary performance optimization:
1253 // only load dictionary if we know an allow list exists for this key
1254 const CFStringRef keyIDs
[3] = {
1255 CFSTR("7C724B39C7C0DB62A54F9BAA183492A2CA838259"),
1256 CFSTR("65F231AD2AF7F7DD52960AC702C10EEFA6D53B11"),
1257 CFSTR("D2A716207CAFD9959EEB430A19F2E0B9740EA8C7")
1259 CFArrayRef result
= NULL
;
1260 bool hasAllowList
= false;
1261 CFIndex count
= (sizeof(keyIDs
) / sizeof(keyIDs
[0]));
1262 for (CFIndex ix
=0; ix
<count
&& authKeyID
; ix
++) {
1263 if (kCFCompareEqualTo
== CFStringCompare(authKeyID
, keyIDs
[ix
], 0)) {
1264 hasAllowList
= true;
1268 if (!hasAllowList
|| !otapkiRef
) {
1272 CFDictionaryRef allowListDict
= SecOTAPKICopyAllowList(otapkiRef
);
1273 if (!allowListDict
) {
1277 // return a retained copy of the allow list array (or NULL)
1278 result
= CFDictionaryGetValue(allowListDict
, authKeyID
);
1279 CFRetainSafe(result
);
1280 CFReleaseSafe(allowListDict
);
1284 CFArrayRef
SecOTAPKICopyTrustedCTLogs(SecOTAPKIRef otapkiRef
)
1286 CFArrayRef result
= NULL
;
1287 if (NULL
== otapkiRef
)
1292 result
= otapkiRef
->_trustedCTLogs
;
1293 CFRetainSafe(result
);
1297 CFArrayRef
SecOTAPKICopyPinningList(SecOTAPKIRef otapkiRef
) {
1298 CFArrayRef result
= NULL
;
1299 if (NULL
== otapkiRef
)
1304 result
= otapkiRef
->_pinningList
;
1305 CFRetainSafe(result
);
1310 /* Returns an array of certificate data (CFDataRef) */
1311 CFArrayRef
SecOTAPKICopyEscrowCertificates(uint32_t escrowRootType
, SecOTAPKIRef otapkiRef
)
1313 CFMutableArrayRef result
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1314 if (NULL
== otapkiRef
) {
1318 switch (escrowRootType
) {
1319 // Note: we shouldn't be getting called to return baseline roots,
1320 // since this function vends production roots by definition.
1321 case kSecCertificateBaselineEscrowRoot
:
1322 case kSecCertificateProductionEscrowRoot
:
1323 case kSecCertificateBaselineEscrowBackupRoot
:
1324 case kSecCertificateProductionEscrowBackupRoot
:
1325 if (otapkiRef
->_escrowCertificates
) {
1326 CFArrayRef escrowCerts
= otapkiRef
->_escrowCertificates
;
1327 CFArrayAppendArray(result
, escrowCerts
, CFRangeMake(0, CFArrayGetCount(escrowCerts
)));
1330 case kSecCertificateBaselineEscrowEnrollmentRoot
:
1331 case kSecCertificateProductionEscrowEnrollmentRoot
:
1332 if (otapkiRef
->_escrowCertificates
) {
1333 // for enrollment purposes, exclude the v100 root
1334 static const unsigned char V100EscrowRoot
[] = {
1335 0x65,0x5C,0xB0,0x3C,0x39,0x3A,0x32,0xA6,0x0B,0x96,
1336 0x40,0xC0,0xCA,0x73,0x41,0xFD,0xC3,0x9E,0x96,0xB3
1338 CFArrayRef escrowCerts
= otapkiRef
->_escrowCertificates
;
1339 CFIndex idx
, count
= CFArrayGetCount(escrowCerts
);
1340 for (idx
=0; idx
< count
; idx
++) {
1341 CFDataRef tmpData
= (CFDataRef
) CFArrayGetValueAtIndex(escrowCerts
, idx
);
1342 SecCertificateRef tmpCert
= (tmpData
) ? SecCertificateCreateWithData(NULL
, tmpData
) : NULL
;
1343 CFDataRef sha1Hash
= (tmpCert
) ? SecCertificateGetSHA1Digest(tmpCert
) : NULL
;
1344 const uint8_t *dp
= (sha1Hash
) ? CFDataGetBytePtr(sha1Hash
) : NULL
;
1345 if (!(dp
&& !memcmp(V100EscrowRoot
, dp
, sizeof(V100EscrowRoot
))) && tmpData
) {
1346 CFArrayAppendValue(result
, tmpData
);
1348 CFReleaseSafe(tmpCert
);
1352 case kSecCertificateBaselinePCSEscrowRoot
:
1353 case kSecCertificateProductionPCSEscrowRoot
:
1354 if (otapkiRef
->_escrowPCSCertificates
) {
1355 CFArrayRef escrowPCSCerts
= otapkiRef
->_escrowPCSCertificates
;
1356 CFArrayAppendArray(result
, escrowPCSCerts
, CFRangeMake(0, CFArrayGetCount(escrowPCSCerts
)));
1367 CFDictionaryRef
SecOTAPKICopyEVPolicyToAnchorMapping(SecOTAPKIRef otapkiRef
)
1369 CFDictionaryRef result
= NULL
;
1370 if (NULL
== otapkiRef
)
1375 result
= otapkiRef
->_evPolicyToAnchorMapping
;
1376 CFRetainSafe(result
);
1381 CFDictionaryRef
SecOTAPKICopyAnchorLookupTable(SecOTAPKIRef otapkiRef
)
1383 CFDictionaryRef result
= NULL
;
1384 if (NULL
== otapkiRef
)
1389 result
= otapkiRef
->_anchorLookupTable
;
1390 CFRetainSafe(result
);
1394 const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef
)
1396 const char* result
= NULL
;
1397 if (NULL
== otapkiRef
)
1402 result
= otapkiRef
->_anchorTable
;
1406 const char* SecOTAPKIGetValidUpdateSnapshot(SecOTAPKIRef otapkiRef
)
1408 const char* result
= NULL
;
1409 if (NULL
== otapkiRef
)
1414 result
= otapkiRef
->_validUpdateSnapshot
;
1418 const char* SecOTAPKIGetValidDatabaseSnapshot(SecOTAPKIRef otapkiRef
)
1420 const char* result
= NULL
;
1421 if (NULL
== otapkiRef
)
1426 result
= otapkiRef
->_validDatabaseSnapshot
;
1430 CFIndex
SecOTAPKIGetValidSnapshotVersion(SecOTAPKIRef otapkiRef
)
1433 if (NULL
== otapkiRef
)
1438 result
= otapkiRef
->_validSnapshotVersion
;
1442 CFIndex
SecOTAPKIGetValidSnapshotFormat(SecOTAPKIRef otapkiRef
)
1445 if (NULL
== otapkiRef
)
1450 result
= otapkiRef
->_validSnapshotFormat
;
1454 int SecOTAPKIGetAssetVersion(SecOTAPKIRef otapkiRef
)
1457 if (NULL
== otapkiRef
)
1462 result
= otapkiRef
->_assetVersion
;
1466 void SecOTAPKIRefreshData()
1468 TestOTALog("In SecOTAPKIRefreshData\n");
1469 SecOTAPKIRef new_otaPKRef
= SecOTACreate();
1470 dispatch_sync(kOTAQueue
,
1472 CFReleaseSafe(kCurrentOTAPKIRef
);
1473 kCurrentOTAPKIRef
= new_otaPKRef
;
1477 /* Returns an array of certificate data (CFDataRef) */
1478 CFArrayRef
SecOTAPKICopyCurrentEscrowCertificates(uint32_t escrowRootType
, CFErrorRef
* error
)
1480 CFArrayRef result
= NULL
;
1482 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
1483 if (NULL
== otapkiref
)
1485 SecError(errSecInternal
, error
, CFSTR("Unable to get the current OTAPKIRef"));
1489 result
= SecOTAPKICopyEscrowCertificates(escrowRootType
, otapkiref
);
1490 CFRelease(otapkiref
);
1494 SecError(errSecInternal
, error
, CFSTR("Could not get escrow certificates from the current OTAPKIRef"));
1499 int SecOTAPKIGetCurrentAssetVersion(CFErrorRef
* error
)
1503 SecOTAPKIRef otapkiref
= SecOTAPKICopyCurrentOTAPKIRef();
1504 if (NULL
== otapkiref
)
1506 SecError(errSecInternal
, error
, CFSTR("Unable to get the current OTAPKIRef"));
1510 result
= otapkiref
->_assetVersion
;
1514 int SecOTAPKISignalNewAsset(CFErrorRef
* error
)
1516 TestOTALog("SecOTAPKISignalNewAsset has been called!\n");
1517 SecOTAPKIRefreshData();