]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/OTATrustUtilities.c
Security-57740.51.3.tar.gz
[apple/security.git] / OSX / sec / securityd / OTATrustUtilities.c
1 /*
2 * Copyright (c) 2003-2004,2006-2010,2013-2016 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * OTATrustUtilities.c
24 */
25
26 #include "OTATrustUtilities.h"
27
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <dirent.h>
35 #include <sys/syslimits.h>
36 #include <sys/mman.h>
37 #include <sys/stat.h>
38 #include <CoreFoundation/CoreFoundation.h>
39 #include <ftw.h>
40 #include "SecFramework.h"
41 #include <pthread.h>
42 #include <sys/param.h>
43 #include <stdlib.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>
52
53 //#define VERBOSE_LOGGING 1
54
55 #if VERBOSE_LOGGING
56
57 static void TestOTALog(const char* sz, ...)
58 {
59 va_list va;
60 va_start(va, sz);
61
62 FILE* fp = fopen("/tmp/secd_OTAUtil.log", "a");
63 if (NULL != fp)
64 {
65 vfprintf(fp, sz, va);
66 fclose(fp);
67 }
68 va_end(va);
69 }
70
71 static void TestOTAResourceLog(const char *msg,
72 CFStringRef resourceName,
73 CFStringRef resourceType,
74 CFStringRef subDirName,
75 CFURLRef url)
76 {
77 CFStringRef tmpStr = NULL;
78 CFIndex maxLength = 0;
79 char *buf = NULL;
80
81 tmpStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
82 CFSTR("%s (name=%@, type=%@, subdir=%@), url=%@"),
83 msg, resourceName, resourceType, subDirName, url);
84 if (tmpStr) {
85 maxLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(tmpStr), kCFStringEncodingUTF8) + 1;
86 buf = (char*) malloc(maxLength);
87 } else {
88 TestOTALog("TestOTAResourceLog: failed to create string of length %ld\n", (long)maxLength);
89 }
90 if (buf) {
91 if (CFStringGetCString(tmpStr, buf, (CFIndex)maxLength, kCFStringEncodingUTF8)) {
92 TestOTALog("%s\n", buf);
93 }
94 free(buf);
95 }
96 CFReleaseSafe(tmpStr);
97 }
98
99 #else
100
101 #define TestOTALog(sz, ...)
102 #define TestOTAResourceLog(msg, resourceName, resourceType, subDirName, url)
103
104 #endif
105
106
107 //#define NEW_LOCATION 1
108
109 #if NEW_LOCATION
110 static const char* kBaseAssetDirectory = "/var/OTAPKI/Assets";
111 #else
112 static const char* kBaseAssetDirectory = "/var/Keychains/Assets";
113 #endif
114
115 static const char* kVersionDirectoryNamePrefix = "Version_";
116 static const char* kNumberString = "%d";
117
118 struct index_record
119 {
120 unsigned char hash[CC_SHA1_DIGEST_LENGTH];
121 uint32_t offset;
122 };
123 typedef struct index_record index_record;
124
125
126 struct _OpaqueSecOTAPKI
127 {
128 CFRuntimeBase _base;
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;
139 const char* _assetPath;
140 int _assetVersion;
141 };
142
143 CFGiblisFor(SecOTAPKI)
144
145 static CF_RETURNS_RETAINED CFStringRef SecOTAPKICopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions)
146 {
147 SecOTAPKIRef otapkiRef = (SecOTAPKIRef)cf;
148 return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTAPKIRef: version %d>"), otapkiRef->_assetVersion);
149 }
150
151 static void SecOTAPKIDestroy(CFTypeRef cf)
152 {
153 SecOTAPKIRef otapkiref = (SecOTAPKIRef)cf;
154
155 CFReleaseNull(otapkiref->_blackListSet);
156 CFReleaseNull(otapkiref->_grayListSet);
157 CFReleaseNull(otapkiref->_escrowCertificates);
158 CFReleaseNull(otapkiref->_escrowPCSCertificates);
159
160 CFReleaseNull(otapkiref->_evPolicyToAnchorMapping);
161 CFReleaseNull(otapkiref->_anchorLookupTable);
162
163 CFReleaseNull(otapkiref->_trustedCTLogs);
164 CFReleaseNull(otapkiref->_CTWhiteListData);
165
166 if (otapkiref->_anchorTable) {
167 free((void *)otapkiref->_anchorTable);
168 otapkiref->_anchorTable = NULL;
169 }
170 if (otapkiref->_assetPath) {
171 free((void *)otapkiref->_assetPath);
172 otapkiref->_assetPath = NULL;
173 }
174 }
175
176 static CFDataRef SecOTACopyFileContents(const char *path)
177 {
178 CFMutableDataRef data = NULL;
179 int fd = open(path, O_RDONLY, 0666);
180
181 if (fd == -1)
182 {
183 goto badFile;
184 }
185
186 off_t fsize = lseek(fd, 0, SEEK_END);
187 if (fsize == (off_t)-1)
188 {
189 goto badFile;
190 }
191
192 if (fsize > (off_t)INT32_MAX)
193 {
194 goto badFile;
195 }
196
197 data = CFDataCreateMutable(kCFAllocatorDefault, (CFIndex)fsize);
198 if (NULL == data)
199 {
200 goto badFile;
201 }
202
203 CFDataSetLength(data, (CFIndex)fsize);
204 void *buf = CFDataGetMutableBytePtr(data);
205 if (NULL == buf)
206 {
207 goto badFile;
208 }
209
210 off_t total_read = 0;
211 while (total_read < fsize)
212 {
213 ssize_t bytes_read;
214
215 bytes_read = pread(fd, buf, (size_t)(fsize - total_read), total_read);
216 if (bytes_read == -1)
217 {
218 goto badFile;
219 }
220 if (bytes_read == 0)
221 {
222 goto badFile;
223 }
224 total_read += bytes_read;
225 }
226
227 close(fd);
228 return data;
229
230 badFile:
231 if (fd != -1)
232 {
233 close(fd);
234 }
235
236 if (data)
237 {
238 CFRelease(data);
239 }
240
241 return NULL;
242 }
243
244 static Boolean PathExists(const char* path, size_t* pFileSize)
245 {
246 TestOTALog("In PathExists: checking path %s\n", path);
247 Boolean result = false;
248 struct stat sb;
249
250 if (NULL != pFileSize)
251 {
252 *pFileSize = 0;
253 }
254
255 int stat_result = stat(path, &sb);
256 result = (stat_result == 0);
257
258
259 if (result)
260 {
261 TestOTALog("In PathExists: stat returned 0 for %s\n", path);
262 if (S_ISDIR(sb.st_mode))
263 {
264 TestOTALog("In PathExists: %s is a directory\n", path);
265 // It is a directory
266 ;
267 }
268 else
269 {
270 TestOTALog("In PathExists: %s is a file\n", path);
271 // It is a file
272 if (NULL != pFileSize)
273 {
274 *pFileSize = (size_t)sb.st_size;
275 }
276 }
277 }
278 #if VERBOSE_LOGGING
279 else
280 {
281 TestOTALog("In PathExists: stat returned %d for %s\n", stat_result, path);
282 int local_errno = errno;
283 switch(local_errno)
284 {
285 case EACCES:
286 TestOTALog("In PathExists: stat failed because of EACCES\n");
287 break;
288
289 case EBADF:
290 TestOTALog("In PathExists: stat failed because of EBADF (Not likely)\n");
291 break;
292
293 case EFAULT:
294 TestOTALog("In PathExists: stat failed because of EFAULT (huh?)\n");
295 break;
296
297 case ELOOP:
298 TestOTALog("In PathExists: stat failed because of ELOOP (huh?)\n");
299 break;
300
301 case ENAMETOOLONG:
302 TestOTALog("In PathExists: stat failed because of ENAMETOOLONG (huh?)\n");
303 break;
304
305 case ENOENT:
306 TestOTALog("In PathExists: stat failed because of ENOENT (missing?)\n");
307 break;
308
309 case ENOMEM:
310 TestOTALog("In PathExists: stat failed because of ENOMEM (really?)\n");
311 break;
312
313 case ENOTDIR:
314 TestOTALog("In PathExists: stat failed because of ENOTDIR (really?)\n");
315 break;
316
317 case EOVERFLOW:
318 TestOTALog("In PathExists: stat failed because of EOVERFLOW (really?)\n");
319 break;
320
321 default:
322 TestOTALog("In PathExists: unknown errno of %d\n", local_errno);
323 break;
324 }
325 }
326 #endif // #if VERBOSE_LOGGING
327
328 return result;
329 }
330
331 static int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
332 {
333 int rv = remove(fpath);
334 return rv;
335 }
336
337 static int rmrf(char *path)
338 {
339 const char* p1 = NULL;
340 char path_buffer[PATH_MAX];
341 memset(path_buffer, 0, sizeof(path_buffer));
342
343 p1 = realpath(path, path_buffer);
344 if (!strncmp(path, p1, PATH_MAX))
345 {
346 return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
347 }
348 return -1;
349 }
350
351
352 static CFStringRef kSecSystemTrustStoreBundlePath = CFSTR("/System/Library/Security/Certificates.bundle");
353
354 CFGiblisGetSingleton(CFBundleRef, SecSystemTrustStoreGetBundle, bundle, ^{
355 CFStringRef bundlePath = NULL;
356 #if TARGET_IPHONE_SIMULATOR
357 char *simulatorRoot = getenv("SIMULATOR_ROOT");
358 if (simulatorRoot)
359 bundlePath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s%@"), simulatorRoot, kSecSystemTrustStoreBundlePath);
360 #endif
361 if (!bundlePath)
362 bundlePath = CFRetainSafe(kSecSystemTrustStoreBundlePath);
363 TestOTAResourceLog("SecSystemTrustStoreGetBundle", bundlePath, NULL, NULL, NULL);
364 CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, bundlePath, kCFURLPOSIXPathStyle, true);
365 *bundle = (url) ? CFBundleCreate(kCFAllocatorDefault, url) : NULL;
366 CFReleaseSafe(url);
367 CFReleaseSafe(bundlePath);
368 })
369
370 static CFURLRef SecSystemTrustStoreCopyResourceURL(CFStringRef resourceName,
371 CFStringRef resourceType, CFStringRef subDirName)
372 {
373 CFURLRef url = NULL;
374 CFBundleRef bundle = SecSystemTrustStoreGetBundle();
375 TestOTALog("SecSystemTrustStoreCopyResourceURL: bundle = %p\n", (void*)bundle);
376 if (bundle) {
377 url = CFBundleCopyResourceURL(bundle, resourceName,
378 resourceType, subDirName);
379 if (!url) {
380 secwarning("resource: %@.%@ in %@ not found", resourceName,
381 resourceType, subDirName);
382 }
383 }
384 if (!url) {
385 TestOTAResourceLog("SecSystemTrustStoreCopyResourceURL: unable to get URL!",
386 resourceName, resourceType, subDirName, url);
387 } else {
388 TestOTAResourceLog("SecSystemTrustStoreCopyResourceURL: got URL from bundle",
389 resourceName, resourceType, subDirName, url);
390 }
391 return url;
392 }
393
394 static CFDataRef SecSystemTrustStoreCopyResourceContents(CFStringRef resourceName,
395 CFStringRef resourceType, CFStringRef subDirName)
396 {
397 CFURLRef url = SecSystemTrustStoreCopyResourceURL(resourceName, resourceType, subDirName);
398 CFDataRef data = NULL;
399 if (url) {
400 SInt32 error;
401 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,
402 url, &data, NULL, NULL, &error)) {
403 secwarning("read: %ld", (long) error);
404 }
405 CFRelease(url);
406 }
407 TestOTALog("SecSystemTrustStoreCopyResourceContents: data = %p\n", data);
408 return data;
409 }
410
411 static CFPropertyListRef CFPropertyListCopyFromAsset(const char *ota_assets_path, CFStringRef asset)
412 {
413 CFPropertyListRef plist = NULL;
414 // Check to see if the <asset>.plist file is in the asset location
415 CFDataRef xmlData = NULL;
416 if (ota_assets_path) {
417 CFStringRef filePath = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s/%@.%@"), ota_assets_path, asset, CFSTR("plist"));
418 CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, filePath, kCFURLPOSIXPathStyle, false);
419
420 plist = CFPropertyListReadFromFile(url);
421 CFReleaseSafe(url);
422 CFReleaseSafe(filePath);
423 }
424
425 if (!plist) {
426 // no OTA asset file, so use the file in the system trust store bundle
427 xmlData = SecSystemTrustStoreCopyResourceContents(asset, CFSTR("plist"), NULL);
428
429 if (xmlData) {
430 plist = CFPropertyListCreateWithData(kCFAllocatorDefault, xmlData, kCFPropertyListImmutable, NULL, NULL);
431 CFRelease(xmlData);
432 }
433 }
434
435 return plist;
436 }
437
438 static CFSetRef CFSetCreateFromPropertyList(CFPropertyListRef plist)
439 {
440 CFSetRef result = NULL;
441
442 if (plist) {
443 CFMutableSetRef tempSet = NULL;
444 if (CFGetTypeID(plist) == CFArrayGetTypeID()) {
445 tempSet = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
446 if (NULL == tempSet) {
447 return result;
448 }
449 CFArrayRef array = (CFArrayRef)plist;
450 CFIndex num_keys = CFArrayGetCount(array);
451 for (CFIndex idx = 0; idx < num_keys; idx++) {
452 CFDataRef data = (CFDataRef)CFArrayGetValueAtIndex(array, idx);
453 CFSetAddValue(tempSet, data);
454 }
455 }
456 else {
457 return result;
458 }
459
460 if (NULL != tempSet) {
461 result = tempSet;
462 }
463 }
464 return result;
465 }
466
467 static const char* InitOTADirectory(int* pAssetVersion)
468 {
469 TestOTALog("In InitOTADirectory\n");
470 const char* result = NULL;
471
472 char buffer[PATH_MAX];
473 DIR *dp;
474 struct dirent *ep;
475 int version = 0;
476 int current_version = 0;
477 int system_asset_version = 0;
478 CFIndex asset_number = 0;
479
480 // Look in the system trust store for an AssetVersion.plist file.
481 // This is needed to ensure that a software update did not put down
482 // a version of the trust store that is greater than the OTA assets.
483
484 CFDataRef assetVersionData = SecSystemTrustStoreCopyResourceContents(CFSTR("AssetVersion"), CFSTR("plist"), NULL);
485 if (NULL != assetVersionData)
486 {
487 CFPropertyListFormat propFormat;
488 CFDictionaryRef versionPlist = CFPropertyListCreateWithData(kCFAllocatorDefault, assetVersionData, 0, &propFormat, NULL);
489 if (NULL != versionPlist && CFDictionaryGetTypeID() == CFGetTypeID(versionPlist))
490 {
491 CFNumberRef versionNumber = (CFNumberRef)CFDictionaryGetValue(versionPlist, (const void *)CFSTR("VersionNumber"));
492 if (NULL != versionNumber)
493 {
494 CFNumberGetValue(versionNumber, kCFNumberCFIndexType, &asset_number);
495 system_asset_version = (int)asset_number;
496 }
497 }
498 CFReleaseSafe(versionPlist);
499 CFReleaseSafe(assetVersionData);
500 }
501
502 // Now check to see if the OTA asset directory exists.
503 // If it does, get the greatest asset number in the OTA asset directory.
504
505 bool assetDirectoryExists = PathExists(kBaseAssetDirectory, NULL);
506 if (assetDirectoryExists)
507 {
508 TestOTALog("InitOTADirectory: %s exists\n", kBaseAssetDirectory);
509 dp = opendir (kBaseAssetDirectory);
510 if (NULL != dp)
511 {
512 TestOTALog("InitOTADirectory: opendir sucessfully open %s\n", kBaseAssetDirectory);
513 while ((ep = readdir(dp)))
514 {
515 TestOTALog("InitOTADirectory: processing name %s\n", ep->d_name);
516 if (strstr(ep->d_name, kVersionDirectoryNamePrefix))
517 {
518 TestOTALog("InitOTADirectory: %s matches\n", ep->d_name);
519 memset(buffer, 0, sizeof(buffer));
520 snprintf(buffer, sizeof(buffer), "%s%s", kVersionDirectoryNamePrefix, kNumberString);
521
522 sscanf(ep->d_name, buffer, &version);
523
524 TestOTALog("InitOTADirectory: version = %d\n", version);
525
526 if (current_version > 0)
527 {
528 if (version > current_version)
529 {
530 // There is more than one Version_ directory.
531 // Delete the one with the smaller version number
532 memset(buffer, 0, sizeof(buffer));
533 snprintf(buffer, sizeof(buffer), "%s/%s%d", kBaseAssetDirectory, kVersionDirectoryNamePrefix, current_version);
534 if (PathExists(buffer, NULL))
535 {
536 rmrf(buffer);
537 }
538 current_version = version;
539 }
540 }
541 else
542 {
543 current_version = version;
544 }
545 }
546 }
547 closedir(dp);
548 }
549 else
550 {
551 TestOTALog("InitOTADirectory: opendir failed to open %s\n", kBaseAssetDirectory);
552 }
553 }
554 else
555 {
556 TestOTALog("InitOTADirectory: PathExists returned false for %s\n", kBaseAssetDirectory);
557 }
558
559 // Check to see which version number is greater.
560 // If the current_version is greater then the OTA asset is newer.
561 // If the system_asset_version is greater than the system asset is newer.
562 if (current_version > system_asset_version)
563 {
564 // The OTA asset is newer than the system asset number
565 memset(buffer, 0, sizeof(buffer));
566 TestOTALog("InitOTADirectory: current_version = %d\n", current_version);
567 snprintf(buffer, sizeof(buffer), "%s/%s%d", kBaseAssetDirectory, kVersionDirectoryNamePrefix, current_version);
568 size_t length = strlen(buffer);
569 char* temp_str = (char*)malloc(length + 1);
570 memset(temp_str, 0, (length + 1));
571 strncpy(temp_str, buffer, length);
572 result = temp_str;
573 }
574 else
575 {
576 // The system asset number is newer than the OTA asset number
577 current_version = system_asset_version;
578 if (NULL != result)
579 {
580 free((void *)result);
581 }
582 result = NULL;
583 }
584
585 if (NULL != pAssetVersion)
586 {
587 *pAssetVersion = current_version;
588 }
589 return result;
590 }
591
592 static CF_RETURNS_RETAINED CFSetRef InitializeBlackList(const char* path_ptr)
593 {
594 CFPropertyListRef plist = CFPropertyListCopyFromAsset(path_ptr, CFSTR("Blocked"));
595 CFSetRef result = CFSetCreateFromPropertyList(plist);
596 CFReleaseSafe(plist);
597
598 return result;
599 }
600
601 static CF_RETURNS_RETAINED CFSetRef InitializeGrayList(const char* path_ptr)
602 {
603 CFPropertyListRef plist = CFPropertyListCopyFromAsset(path_ptr, CFSTR("GrayListedKeys"));
604 CFSetRef result = CFSetCreateFromPropertyList(plist);
605 CFReleaseSafe(plist);
606
607 return result;
608 }
609
610 static CF_RETURNS_RETAINED CFDataRef InitializeCTWhiteListData(const char* path_ptr)
611 {
612 CFPropertyListRef data = CFPropertyListCopyFromAsset(path_ptr, CFSTR("CTWhiteListData"));
613
614 if (data && (CFGetTypeID(data) == CFDataGetTypeID())) {
615 return data;
616 } else {
617 CFReleaseNull(data);
618 return NULL;
619 }
620 }
621
622 static CF_RETURNS_RETAINED CFDictionaryRef InitializeAllowList(const char* path_ptr)
623 {
624 CFPropertyListRef allowList = CFPropertyListCopyFromAsset(path_ptr, CFSTR("Allowed"));
625
626 if (allowList && (CFGetTypeID(allowList) == CFDictionaryGetTypeID())) {
627 return allowList;
628 } else {
629 CFReleaseNull(allowList);
630 return NULL;
631 }
632 }
633
634 static CF_RETURNS_RETAINED CFArrayRef InitializeTrustedCTLogs(const char* path_ptr)
635 {
636 CFPropertyListRef trustedCTLogs = CFPropertyListCopyFromAsset(path_ptr, CFSTR("TrustedCTLogs"));
637
638 if (trustedCTLogs && (CFGetTypeID(trustedCTLogs) == CFArrayGetTypeID())) {
639 return trustedCTLogs;
640 } else {
641 CFReleaseNull(trustedCTLogs);
642 return NULL;
643 }
644 }
645
646 static CF_RETURNS_RETAINED CFDictionaryRef InitializeEVPolicyToAnchorDigestsTable(const char* path_ptr)
647 {
648 CFDictionaryRef result = NULL;
649 CFPropertyListRef evroots = CFPropertyListCopyFromAsset(path_ptr, CFSTR("EVRoots"));
650
651 if (evroots) {
652 if (CFGetTypeID(evroots) == CFDictionaryGetTypeID()) {
653 /* @@@ Ensure that each dictionary key is a dotted list of digits,
654 each value is an NSArrayRef and each element in the array is a
655 20 byte digest. */
656 result = (CFDictionaryRef)evroots;
657 }
658 else {
659 secwarning("EVRoot.plist is wrong type.");
660 CFRelease(evroots);
661 }
662 }
663
664 return result;
665 }
666
667 static void* MapFile(const char* path, int* out_fd, size_t* out_file_size)
668 {
669 void* result = NULL;
670 void* temp_result = NULL;
671 if (NULL == path || NULL == out_fd || NULL == out_file_size)
672 {
673 return result;
674 }
675
676 *out_fd = -1;
677 *out_file_size = 0;
678
679
680 *out_fd = open(path, O_RDONLY, 0666);
681
682 if (*out_fd == -1)
683 {
684 return result;
685 }
686
687 off_t fsize = lseek(*out_fd, 0, SEEK_END);
688 if (fsize == (off_t)-1)
689 {
690 return result;
691 }
692
693 if (fsize > (off_t)INT32_MAX)
694 {
695 close(*out_fd);
696 *out_fd = -1;
697 return result;
698 }
699
700 size_t malloc_size = (size_t)fsize;
701
702 temp_result = malloc(malloc_size);
703 if (NULL == temp_result)
704 {
705 close(*out_fd);
706 *out_fd = -1;
707 return result;
708 }
709
710 *out_file_size = malloc_size;
711
712 off_t total_read = 0;
713 while (total_read < fsize)
714 {
715 ssize_t bytes_read;
716
717 bytes_read = pread(*out_fd, temp_result, (size_t)(fsize - total_read), total_read);
718 if (bytes_read == -1)
719 {
720 free(temp_result);
721 temp_result = NULL;
722 close(*out_fd);
723 *out_fd = -1;
724 return result;
725 }
726 if (bytes_read == 0)
727 {
728 free(temp_result);
729 temp_result = NULL;
730 close(*out_fd);
731 *out_fd = -1;
732 return result;
733 }
734 total_read += bytes_read;
735 }
736
737 if (NULL != temp_result)
738 {
739 result = temp_result;
740 }
741
742 return result;
743 }
744
745 static void UnMapFile(void* mapped_data, size_t data_size)
746 {
747 #pragma unused(mapped_data, data_size)
748 if (NULL != mapped_data)
749 {
750 free((void *)mapped_data);
751 mapped_data = NULL;
752 }
753 }
754
755 static bool InitializeAnchorTable(const char* path_ptr, CFDictionaryRef* pLookupTable, const char** ppAnchorTable)
756 {
757
758 bool result = false;
759
760 if (NULL == pLookupTable || NULL == ppAnchorTable)
761 {
762 return result;
763 }
764
765 *pLookupTable = NULL;
766 *ppAnchorTable = NULL;;
767
768 const char* dir_path = NULL;
769 CFDataRef cert_index_file_data = NULL;
770 char file_path_buffer[PATH_MAX];
771 CFURLRef table_data_url = NULL;
772 CFStringRef table_data_cstr_path = NULL;
773 const char* table_data_path = NULL;
774 const index_record* pIndex = NULL;
775 size_t index_offset = 0;
776 size_t index_data_size = 0;
777 CFMutableDictionaryRef anchorLookupTable = NULL;
778 uint32_t offset_int_value = 0;
779 CFNumberRef index_offset_value = NULL;
780 CFDataRef index_hash = NULL;
781 CFMutableArrayRef offsets = NULL;
782 Boolean release_offset = false;
783
784 char* local_anchorTable = NULL;
785 size_t local_anchorTableSize = 0;
786 int local_anchorTable_fd = -1;
787
788 // ------------------------------------------------------------------------
789 // First determine if there are asset files at /var/Keychains. If there
790 // are files use them for the trust table. Otherwise, use the files in the
791 // Security.framework bundle.
792 //
793 // The anchor table file is mapped into memory. This SHOULD be OK as the
794 // size of the data is around 250K.
795 // ------------------------------------------------------------------------
796 dir_path = path_ptr;
797
798 if (NULL != dir_path)
799 {
800 // There is a set of OTA asset files
801 memset(file_path_buffer, 0, PATH_MAX);
802 snprintf(file_path_buffer, PATH_MAX, "%s/certsIndex.data", dir_path);
803 cert_index_file_data = SecOTACopyFileContents(file_path_buffer);
804
805 if (NULL != cert_index_file_data)
806 {
807 memset(file_path_buffer, 0, PATH_MAX);
808 snprintf(file_path_buffer, PATH_MAX, "%s/certsTable.data", dir_path);
809 local_anchorTable = (char *)MapFile(file_path_buffer, &local_anchorTable_fd, &local_anchorTableSize);
810 }
811
812 free((void *)dir_path);
813 dir_path = NULL;
814 }
815
816 // Check to see if kAnchorTable was indeed set
817 if (NULL == local_anchorTable)
818 {
819 // local_anchorTable is still NULL so the asset in the system trust store bundle needs to be used.
820 CFReleaseSafe(cert_index_file_data);
821 cert_index_file_data = SecSystemTrustStoreCopyResourceContents(CFSTR("certsIndex"), CFSTR("data"), NULL);
822 if (!cert_index_file_data) {
823 secerror("could not find certsIndex");
824 }
825 table_data_url = SecSystemTrustStoreCopyResourceURL(CFSTR("certsTable"), CFSTR("data"), NULL);
826 if (!table_data_url) {
827 secerror("could not find certsTable");
828 }
829
830 if (NULL != table_data_url)
831 {
832 table_data_cstr_path = CFURLCopyFileSystemPath(table_data_url, kCFURLPOSIXPathStyle);
833 if (NULL != table_data_cstr_path)
834 {
835 memset(file_path_buffer, 0, PATH_MAX);
836 table_data_path = CFStringGetCStringPtr(table_data_cstr_path, kCFStringEncodingUTF8);
837 if (NULL == table_data_path)
838 {
839 if (CFStringGetCString(table_data_cstr_path, file_path_buffer, PATH_MAX, kCFStringEncodingUTF8))
840 {
841 table_data_path = file_path_buffer;
842 }
843 }
844 local_anchorTable = (char *)MapFile(table_data_path, &local_anchorTable_fd, &local_anchorTableSize);
845 CFReleaseSafe(table_data_cstr_path);
846 }
847 }
848 CFReleaseSafe(table_data_url);
849 }
850
851 if (NULL == local_anchorTable || NULL == cert_index_file_data)
852 {
853 // we are in trouble
854 if (NULL != local_anchorTable)
855 {
856 UnMapFile(local_anchorTable, local_anchorTableSize);
857 local_anchorTable = NULL;
858 local_anchorTableSize = 0;
859 }
860 CFReleaseSafe(cert_index_file_data);
861 return result;
862 }
863
864 // ------------------------------------------------------------------------
865 // Now that the locations of the files are known and the table file has
866 // been mapped into memory, create a dictionary that maps the SHA1 hash of
867 // normalized issuer to the offset in the mapped anchor table file which
868 // contains a index_record to the correct certificate
869 // ------------------------------------------------------------------------
870 pIndex = (const index_record*)CFDataGetBytePtr(cert_index_file_data);
871 index_data_size = CFDataGetLength(cert_index_file_data);
872
873 anchorLookupTable = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
874 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
875
876 for (index_offset = index_data_size; index_offset > 0; index_offset -= sizeof(index_record), pIndex++)
877 {
878 offset_int_value = pIndex->offset;
879
880 index_offset_value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &offset_int_value);
881 index_hash = CFDataCreate(kCFAllocatorDefault, pIndex->hash, CC_SHA1_DIGEST_LENGTH);
882
883 // see if the dictionary already has this key
884 release_offset = false;
885 offsets = (CFMutableArrayRef)CFDictionaryGetValue(anchorLookupTable, index_hash);
886 if (NULL == offsets)
887 {
888 offsets = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
889 release_offset = true;
890 }
891
892 // Add the offset
893 CFArrayAppendValue(offsets, index_offset_value);
894
895 // set the key value pair in the dictionary
896 CFDictionarySetValue(anchorLookupTable, index_hash, offsets);
897
898 CFRelease(index_offset_value);
899 CFRelease(index_hash);
900 if (release_offset)
901 {
902 CFRelease(offsets);
903 }
904 }
905
906 CFRelease(cert_index_file_data);
907
908 if (NULL != anchorLookupTable && NULL != local_anchorTable)
909 {
910 *pLookupTable = anchorLookupTable;
911 *ppAnchorTable = local_anchorTable;
912 result = true;
913 }
914 else
915 {
916 CFReleaseSafe(anchorLookupTable);
917 if (NULL != local_anchorTable)
918 {
919 UnMapFile(local_anchorTable, local_anchorTableSize);
920 //munmap(kAnchorTable, local_anchorTableSize);
921 local_anchorTable = NULL;
922 local_anchorTableSize = 0;
923 }
924 }
925
926 return result;
927 }
928
929 static void InitializeEscrowCertificates(const char* path_ptr, CFArrayRef *escrowRoots, CFArrayRef *escrowPCSRoots)
930 {
931 CFDataRef file_data = NULL;
932
933 const char* dir_path = path_ptr;
934 if (NULL == dir_path)
935 {
936 file_data = SecSystemTrustStoreCopyResourceContents(CFSTR("AppleESCertificates"), CFSTR("plist"), NULL);
937 }
938 else
939 {
940 char buffer[1024];
941 memset(buffer, 0, 1024);
942 snprintf(buffer, 1024, "%s/AppleESCertificates.plist", dir_path);
943 file_data = SecOTACopyFileContents(buffer);
944 }
945
946 if (NULL != file_data)
947 {
948 CFPropertyListFormat propFormat;
949 CFDictionaryRef certsDictionary = CFPropertyListCreateWithData(kCFAllocatorDefault, file_data, 0, &propFormat, NULL);
950 if (NULL != certsDictionary && CFDictionaryGetTypeID() == CFGetTypeID((CFTypeRef)certsDictionary))
951 {
952 CFArrayRef certs = (CFArrayRef)CFDictionaryGetValue(certsDictionary, CFSTR("ProductionEscrowKey"));
953 if (NULL != certs && CFArrayGetTypeID() == CFGetTypeID((CFTypeRef)certs) && CFArrayGetCount(certs) > 0)
954 {
955 *escrowRoots = CFArrayCreateCopy(kCFAllocatorDefault, certs);
956 }
957 CFArrayRef pcs_certs = (CFArrayRef)CFDictionaryGetValue(certsDictionary, CFSTR("ProductionPCSEscrowKey"));
958 if (NULL != pcs_certs && CFArrayGetTypeID() == CFGetTypeID((CFTypeRef)pcs_certs) && CFArrayGetCount(pcs_certs) > 0)
959 {
960 *escrowPCSRoots = CFArrayCreateCopy(kCFAllocatorDefault, pcs_certs);
961 }
962 }
963 CFReleaseSafe(certsDictionary);
964 CFRelease(file_data);
965 }
966
967 }
968
969
970 static SecOTAPKIRef SecOTACreate()
971 {
972 TestOTALog("In SecOTACreate\n");
973
974 SecOTAPKIRef otapkiref = NULL;
975
976 otapkiref = CFTypeAllocate(SecOTAPKI, struct _OpaqueSecOTAPKI , kCFAllocatorDefault);
977
978 if (NULL == otapkiref)
979 {
980 return otapkiref;
981 }
982
983 // Make sure that if this routine has to bail that the clean up
984 // will do the right thing
985 otapkiref->_blackListSet = NULL;
986 otapkiref->_grayListSet = NULL;
987 otapkiref->_allowList = NULL;
988 otapkiref->_trustedCTLogs = NULL;
989 otapkiref->_CTWhiteListData = NULL;
990 otapkiref->_escrowCertificates = NULL;
991 otapkiref->_escrowPCSCertificates = NULL;
992 otapkiref->_evPolicyToAnchorMapping = NULL;
993 otapkiref->_anchorLookupTable = NULL;
994 otapkiref->_anchorTable = NULL;
995 otapkiref->_assetPath = NULL;
996 otapkiref->_assetVersion = 0;
997
998 // Start off by getting the correct asset directory info
999 int asset_version = 0;
1000 const char* path_ptr = InitOTADirectory(&asset_version);
1001 otapkiref->_assetPath = path_ptr;
1002 otapkiref->_assetVersion = asset_version;
1003
1004 TestOTALog("SecOTACreate: asset_path = %s\n", path_ptr);
1005 TestOTALog("SecOTACreate: asset_version = %d\n", asset_version);
1006
1007 // Get the set of black listed keys
1008 CFSetRef blackKeysSet = InitializeBlackList(path_ptr);
1009 if (NULL == blackKeysSet)
1010 {
1011 CFReleaseNull(otapkiref);
1012 return otapkiref;
1013 }
1014 otapkiref->_blackListSet = blackKeysSet;
1015
1016 // Get the set of gray listed keys
1017 CFSetRef grayKeysSet = InitializeGrayList(path_ptr);
1018 if (NULL == grayKeysSet)
1019 {
1020 CFReleaseNull(otapkiref);
1021 return otapkiref;
1022 }
1023 otapkiref->_grayListSet = grayKeysSet;
1024
1025 // Get the allow list dictionary
1026 // (now loaded lazily in SecOTAPKICopyAllowList)
1027
1028 // Get the trusted Certificate Transparency Logs
1029 otapkiref->_trustedCTLogs = InitializeTrustedCTLogs(path_ptr);
1030
1031 // Get the EV whitelist
1032 otapkiref->_CTWhiteListData = InitializeCTWhiteListData(path_ptr);
1033
1034 CFArrayRef escrowCerts = NULL;
1035 CFArrayRef escrowPCSCerts = NULL;
1036 InitializeEscrowCertificates(path_ptr, &escrowCerts, &escrowPCSCerts);
1037 if (NULL == escrowCerts || NULL == escrowPCSCerts)
1038 {
1039 CFReleaseNull(escrowCerts);
1040 CFReleaseNull(escrowPCSCerts);
1041 CFReleaseNull(otapkiref);
1042 return otapkiref;
1043 }
1044 otapkiref->_escrowCertificates = escrowCerts;
1045 otapkiref->_escrowPCSCertificates = escrowPCSCerts;
1046
1047 // Get the mapping of EV Policy OIDs to Anchor digest
1048 CFDictionaryRef evOidToAnchorDigestMap = InitializeEVPolicyToAnchorDigestsTable(path_ptr);
1049 if (NULL == evOidToAnchorDigestMap)
1050 {
1051 CFReleaseNull(otapkiref);
1052 return otapkiref;
1053 }
1054 otapkiref->_evPolicyToAnchorMapping = evOidToAnchorDigestMap;
1055
1056 CFDictionaryRef anchorLookupTable = NULL;
1057 const char* anchorTablePtr = NULL;
1058
1059 if (!InitializeAnchorTable(path_ptr, &anchorLookupTable, &anchorTablePtr))
1060 {
1061 CFReleaseSafe(anchorLookupTable);
1062 if (anchorTablePtr) {
1063 free((void *)anchorTablePtr);
1064 }
1065 CFReleaseNull(otapkiref);
1066 return otapkiref;
1067 }
1068 otapkiref->_anchorLookupTable = anchorLookupTable;
1069 otapkiref->_anchorTable = anchorTablePtr;
1070 return otapkiref;
1071 }
1072
1073 static dispatch_once_t kInitializeOTAPKI = 0;
1074 static const char* kOTAQueueLabel = "com.apple.security.OTAPKIQueue";
1075 static dispatch_queue_t kOTAQueue;
1076 static SecOTAPKIRef kCurrentOTAPKIRef = NULL;
1077
1078 SecOTAPKIRef SecOTAPKICopyCurrentOTAPKIRef()
1079 {
1080 __block SecOTAPKIRef result = NULL;
1081 dispatch_once(&kInitializeOTAPKI,
1082 ^{
1083 kOTAQueue = dispatch_queue_create(kOTAQueueLabel, NULL);
1084 kCurrentOTAPKIRef = SecOTACreate();
1085 });
1086
1087 dispatch_sync(kOTAQueue,
1088 ^{
1089 result = kCurrentOTAPKIRef;
1090 CFRetainSafe(result);
1091 });
1092 return result;
1093 }
1094
1095
1096 CFSetRef SecOTAPKICopyBlackListSet(SecOTAPKIRef otapkiRef)
1097 {
1098 CFSetRef result = NULL;
1099 if (NULL == otapkiRef)
1100 {
1101 return result;
1102 }
1103
1104 result = otapkiRef->_blackListSet;
1105 CFRetainSafe(result);
1106 return result;
1107 }
1108
1109
1110 CFSetRef SecOTAPKICopyGrayList(SecOTAPKIRef otapkiRef)
1111 {
1112 CFSetRef result = NULL;
1113 if (NULL == otapkiRef)
1114 {
1115 return result;
1116 }
1117
1118 result = otapkiRef->_grayListSet;
1119 CFRetainSafe(result);
1120 return result;
1121 }
1122
1123 CFDictionaryRef SecOTAPKICopyAllowList(SecOTAPKIRef otapkiRef)
1124 {
1125 CFDictionaryRef result = NULL;
1126 if (NULL == otapkiRef)
1127 {
1128 return result;
1129 }
1130
1131 result = otapkiRef->_allowList;
1132 if (!result) {
1133 result = InitializeAllowList(otapkiRef->_assetPath);
1134 otapkiRef->_allowList = result;
1135 }
1136
1137 CFRetainSafe(result);
1138 return result;
1139 }
1140
1141 CFArrayRef SecOTAPKICopyAllowListForAuthKeyID(SecOTAPKIRef otapkiRef, CFStringRef authKeyID)
1142 {
1143 // %%% temporary performance optimization:
1144 // only load dictionary if we know an allow list exists for this key
1145 const CFStringRef keyIDs[3] = {
1146 CFSTR("7C724B39C7C0DB62A54F9BAA183492A2CA838259"),
1147 CFSTR("65F231AD2AF7F7DD52960AC702C10EEFA6D53B11"),
1148 CFSTR("D2A716207CAFD9959EEB430A19F2E0B9740EA8C7")
1149 };
1150 CFArrayRef result = NULL;
1151 bool hasAllowList = false;
1152 CFIndex count = (sizeof(keyIDs) / sizeof(keyIDs[0]));
1153 for (CFIndex ix=0; ix<count && authKeyID; ix++) {
1154 if (kCFCompareEqualTo == CFStringCompare(authKeyID, keyIDs[ix], 0)) {
1155 hasAllowList = true;
1156 break;
1157 }
1158 }
1159 if (!hasAllowList || !otapkiRef) {
1160 return result;
1161 }
1162
1163 CFDictionaryRef allowListDict = SecOTAPKICopyAllowList(otapkiRef);
1164 if (!allowListDict) {
1165 return result;
1166 }
1167
1168 // return a retained copy of the allow list array (or NULL)
1169 result = CFDictionaryGetValue(allowListDict, authKeyID);
1170 CFRetainSafe(result);
1171 CFReleaseSafe(allowListDict);
1172 return result;
1173 }
1174
1175 CFArrayRef SecOTAPKICopyTrustedCTLogs(SecOTAPKIRef otapkiRef)
1176 {
1177 CFArrayRef result = NULL;
1178 if (NULL == otapkiRef)
1179 {
1180 return result;
1181 }
1182
1183 result = otapkiRef->_trustedCTLogs;
1184 CFRetainSafe(result);
1185 return result;
1186 }
1187
1188 CFDataRef SecOTAPKICopyCTWhiteList(SecOTAPKIRef otapkiRef)
1189 {
1190 CFDataRef result = NULL;
1191 if (NULL == otapkiRef)
1192 {
1193 return result;
1194 }
1195
1196 result = otapkiRef->_CTWhiteListData;
1197 CFRetainSafe(result);
1198 return result;
1199 }
1200
1201
1202 /* Returns an array of certificate data (CFDataRef) */
1203 CFArrayRef SecOTAPKICopyEscrowCertificates(uint32_t escrowRootType, SecOTAPKIRef otapkiRef)
1204 {
1205 CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1206 if (NULL == otapkiRef) {
1207 return result;
1208 }
1209
1210 switch (escrowRootType) {
1211 // Note: we shouldn't be getting called to return baseline roots,
1212 // since this function vends production roots by definition.
1213 case kSecCertificateBaselineEscrowRoot:
1214 case kSecCertificateProductionEscrowRoot:
1215 case kSecCertificateBaselineEscrowBackupRoot:
1216 case kSecCertificateProductionEscrowBackupRoot:
1217 if (otapkiRef->_escrowCertificates) {
1218 CFArrayRef escrowCerts = otapkiRef->_escrowCertificates;
1219 CFArrayAppendArray(result, escrowCerts, CFRangeMake(0, CFArrayGetCount(escrowCerts)));
1220 }
1221 break;
1222 case kSecCertificateBaselineEscrowEnrollmentRoot:
1223 case kSecCertificateProductionEscrowEnrollmentRoot:
1224 if (otapkiRef->_escrowCertificates) {
1225 // for enrollment purposes, exclude the v100 root
1226 static const unsigned char V100EscrowRoot[] = {
1227 0x65,0x5C,0xB0,0x3C,0x39,0x3A,0x32,0xA6,0x0B,0x96,
1228 0x40,0xC0,0xCA,0x73,0x41,0xFD,0xC3,0x9E,0x96,0xB3
1229 };
1230 CFArrayRef escrowCerts = otapkiRef->_escrowCertificates;
1231 CFIndex idx, count = CFArrayGetCount(escrowCerts);
1232 for (idx=0; idx < count; idx++) {
1233 CFDataRef tmpData = (CFDataRef) CFArrayGetValueAtIndex(escrowCerts, idx);
1234 SecCertificateRef tmpCert = (tmpData) ? SecCertificateCreateWithData(NULL, tmpData) : NULL;
1235 CFDataRef sha1Hash = (tmpCert) ? SecCertificateGetSHA1Digest(tmpCert) : NULL;
1236 const uint8_t *dp = (sha1Hash) ? CFDataGetBytePtr(sha1Hash) : NULL;
1237 if (!(dp && !memcmp(V100EscrowRoot, dp, sizeof(V100EscrowRoot))) && tmpData) {
1238 CFArrayAppendValue(result, tmpData);
1239 }
1240 CFReleaseSafe(tmpCert);
1241 }
1242 }
1243 break;
1244 case kSecCertificateBaselinePCSEscrowRoot:
1245 case kSecCertificateProductionPCSEscrowRoot:
1246 if (otapkiRef->_escrowPCSCertificates) {
1247 CFArrayRef escrowPCSCerts = otapkiRef->_escrowPCSCertificates;
1248 CFArrayAppendArray(result, escrowPCSCerts, CFRangeMake(0, CFArrayGetCount(escrowPCSCerts)));
1249 }
1250 break;
1251 default:
1252 break;
1253 }
1254
1255 return result;
1256 }
1257
1258
1259 CFDictionaryRef SecOTAPKICopyEVPolicyToAnchorMapping(SecOTAPKIRef otapkiRef)
1260 {
1261 CFDictionaryRef result = NULL;
1262 if (NULL == otapkiRef)
1263 {
1264 return result;
1265 }
1266
1267 result = otapkiRef->_evPolicyToAnchorMapping;
1268 CFRetainSafe(result);
1269 return result;
1270 }
1271
1272
1273 CFDictionaryRef SecOTAPKICopyAnchorLookupTable(SecOTAPKIRef otapkiRef)
1274 {
1275 CFDictionaryRef result = NULL;
1276 if (NULL == otapkiRef)
1277 {
1278 return result;
1279 }
1280
1281 result = otapkiRef->_anchorLookupTable;
1282 CFRetainSafe(result);
1283 return result;
1284 }
1285
1286 const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef)
1287 {
1288 const char* result = NULL;
1289 if (NULL == otapkiRef)
1290 {
1291 return result;
1292 }
1293
1294 result = otapkiRef->_anchorTable;
1295 return result;
1296 }
1297
1298 int SecOTAPKIGetAssetVersion(SecOTAPKIRef otapkiRef)
1299 {
1300 int result = 0;
1301 if (NULL == otapkiRef)
1302 {
1303 return result;
1304 }
1305
1306 result = otapkiRef->_assetVersion;
1307 return result;
1308 }
1309
1310 void SecOTAPKIRefreshData()
1311 {
1312 TestOTALog("In SecOTAPKIRefreshData\n");
1313 SecOTAPKIRef new_otaPKRef = SecOTACreate();
1314 dispatch_sync(kOTAQueue,
1315 ^{
1316 CFReleaseSafe(kCurrentOTAPKIRef);
1317 kCurrentOTAPKIRef = new_otaPKRef;
1318 });
1319 }
1320
1321 /* Returns an array of certificate data (CFDataRef) */
1322 CFArrayRef SecOTAPKICopyCurrentEscrowCertificates(uint32_t escrowRootType, CFErrorRef* error)
1323 {
1324 CFArrayRef result = NULL;
1325
1326 SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
1327 if (NULL == otapkiref)
1328 {
1329 SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef"));
1330 return result;
1331 }
1332
1333 result = SecOTAPKICopyEscrowCertificates(escrowRootType, otapkiref);
1334 CFRelease(otapkiref);
1335
1336 if (NULL == result)
1337 {
1338 SecError(errSecInternal, error, CFSTR("Could not get escrow certificates from the current OTAPKIRef"));
1339 }
1340 return result;
1341 }
1342
1343 int SecOTAPKIGetCurrentAssetVersion(CFErrorRef* error)
1344 {
1345 int result = 0;
1346
1347 SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
1348 if (NULL == otapkiref)
1349 {
1350 SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef"));
1351 return result;
1352 }
1353
1354 result = otapkiref->_assetVersion;
1355 return result;
1356 }
1357
1358 int SecOTAPKISignalNewAsset(CFErrorRef* error)
1359 {
1360 TestOTALog("SecOTAPKISignalNewAsset has been called!\n");
1361 SecOTAPKIRefreshData();
1362 return 1;
1363 }