]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/OTATrustUtilities.c
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / sec / securityd / OTATrustUtilities.c
1 /*
2 * Copyright (c) 2003-2004,2006-2010,2013-2017 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 CFArrayRef _pinningList;
134 CFArrayRef _escrowCertificates;
135 CFArrayRef _escrowPCSCertificates;
136 CFDictionaryRef _evPolicyToAnchorMapping;
137 CFDictionaryRef _anchorLookupTable;
138 const char* _anchorTable;
139 const char* _assetPath;
140 int _assetVersion;
141 const char* _validUpdateSnapshot;
142 const char* _validDatabaseSnapshot;
143 CFIndex _validSnapshotVersion;
144 CFIndex _validSnapshotFormat;
145 };
146
147 CFGiblisFor(SecOTAPKI)
148
149 static CF_RETURNS_RETAINED CFStringRef SecOTAPKICopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions)
150 {
151 SecOTAPKIRef otapkiRef = (SecOTAPKIRef)cf;
152 return CFStringCreateWithFormat(kCFAllocatorDefault,NULL,CFSTR("<SecOTAPKIRef: version %d>"), otapkiRef->_assetVersion);
153 }
154
155 static void SecOTAPKIDestroy(CFTypeRef cf)
156 {
157 SecOTAPKIRef otapkiref = (SecOTAPKIRef)cf;
158
159 CFReleaseNull(otapkiref->_blackListSet);
160 CFReleaseNull(otapkiref->_grayListSet);
161 CFReleaseNull(otapkiref->_escrowCertificates);
162 CFReleaseNull(otapkiref->_escrowPCSCertificates);
163
164 CFReleaseNull(otapkiref->_evPolicyToAnchorMapping);
165 CFReleaseNull(otapkiref->_anchorLookupTable);
166
167 CFReleaseNull(otapkiref->_trustedCTLogs);
168 CFReleaseNull(otapkiref->_pinningList);
169
170 if (otapkiref->_anchorTable) {
171 free((void *)otapkiref->_anchorTable);
172 otapkiref->_anchorTable = NULL;
173 }
174 if (otapkiref->_assetPath) {
175 free((void *)otapkiref->_assetPath);
176 otapkiref->_assetPath = NULL;
177 }
178 if (otapkiref->_validUpdateSnapshot) {
179 free((void *)otapkiref->_validUpdateSnapshot);
180 otapkiref->_validUpdateSnapshot = NULL;
181 }
182 if (otapkiref->_validDatabaseSnapshot) {
183 free((void *)otapkiref->_validDatabaseSnapshot);
184 otapkiref->_validDatabaseSnapshot = NULL;
185 }
186 }
187
188 static CFDataRef SecOTACopyFileContents(const char *path)
189 {
190 CFMutableDataRef data = NULL;
191 int fd = open(path, O_RDONLY, 0666);
192
193 if (fd == -1)
194 {
195 goto badFile;
196 }
197
198 off_t fsize = lseek(fd, 0, SEEK_END);
199 if (fsize == (off_t)-1)
200 {
201 goto badFile;
202 }
203
204 if (fsize > (off_t)INT32_MAX)
205 {
206 goto badFile;
207 }
208
209 data = CFDataCreateMutable(kCFAllocatorDefault, (CFIndex)fsize);
210 if (NULL == data)
211 {
212 goto badFile;
213 }
214
215 CFDataSetLength(data, (CFIndex)fsize);
216 void *buf = CFDataGetMutableBytePtr(data);
217 if (NULL == buf)
218 {
219 goto badFile;
220 }
221
222 off_t total_read = 0;
223 while (total_read < fsize)
224 {
225 ssize_t bytes_read;
226
227 bytes_read = pread(fd, buf, (size_t)(fsize - total_read), total_read);
228 if (bytes_read == -1)
229 {
230 goto badFile;
231 }
232 if (bytes_read == 0)
233 {
234 goto badFile;
235 }
236 total_read += bytes_read;
237 }
238
239 close(fd);
240 return data;
241
242 badFile:
243 if (fd != -1)
244 {
245 close(fd);
246 }
247
248 if (data)
249 {
250 CFRelease(data);
251 }
252
253 return NULL;
254 }
255
256 static Boolean PathExists(const char* path, size_t* pFileSize)
257 {
258 const char *checked_path = (path) ? path : "";
259 TestOTALog("In PathExists: checking path \"%s\"\n", checked_path);
260 Boolean result = false;
261 struct stat sb;
262
263 if (NULL != pFileSize)
264 {
265 *pFileSize = 0;
266 }
267
268 int stat_result = stat(checked_path, &sb);
269 result = (stat_result == 0);
270
271
272 if (result)
273 {
274 TestOTALog("In PathExists: stat returned 0 for \"%s\"\n", checked_path);
275 if (S_ISDIR(sb.st_mode))
276 {
277 TestOTALog("In PathExists: \"%s\" is a directory\n", checked_path);
278 // It is a directory
279 ;
280 }
281 else
282 {
283 TestOTALog("In PathExists: \"%s\" is a file\n", checked_path);
284 // It is a file
285 if (NULL != pFileSize)
286 {
287 *pFileSize = (size_t)sb.st_size;
288 }
289 }
290 }
291 #if VERBOSE_LOGGING
292 else
293 {
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;
297 switch(local_errno)
298 {
299 case EACCES:
300 TestOTALog("%s EACCES\n", stat_prefix);
301 break;
302
303 case EBADF:
304 TestOTALog("%s EBADF\n", stat_prefix);
305 break;
306
307 case EFAULT:
308 TestOTALog("%s EFAULT\n", stat_prefix);
309 break;
310
311 case ELOOP:
312 TestOTALog("%s ELOOP\n", stat_prefix);
313 break;
314
315 case ENAMETOOLONG:
316 TestOTALog("%s ENAMETOOLONG\n", stat_prefix);
317 break;
318
319 case ENOENT:
320 TestOTALog("%s ENOENT (missing?)\n", stat_prefix);
321 break;
322
323 case ENOMEM:
324 TestOTALog("%s ENOMEM\n", stat_prefix);
325 break;
326
327 case ENOTDIR:
328 TestOTALog("%s ENOTDIR\n", stat_prefix);
329 break;
330
331 case EOVERFLOW:
332 TestOTALog("%s EOVERFLOW\n", stat_prefix);
333 break;
334
335 default:
336 TestOTALog("%s %d\n", stat_prefix, local_errno);
337 break;
338 }
339 }
340 #endif // #if VERBOSE_LOGGING
341
342 return result;
343 }
344
345 static int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
346 {
347 int rv = remove(fpath);
348 return rv;
349 }
350
351 static int rmrf(char *path)
352 {
353 const char* p1 = NULL;
354 char path_buffer[PATH_MAX];
355 memset(path_buffer, 0, sizeof(path_buffer));
356
357 p1 = realpath(path, path_buffer);
358 if (p1 && !strncmp(path, p1, PATH_MAX))
359 {
360 return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
361 }
362 return -1;
363 }
364
365
366 static CFStringRef kSecSystemTrustStoreBundlePath = CFSTR("/System/Library/Security/Certificates.bundle");
367
368 CFGiblisGetSingleton(CFBundleRef, SecSystemTrustStoreGetBundle, bundle, ^{
369 CFStringRef bundlePath = NULL;
370 #if TARGET_IPHONE_SIMULATOR
371 char *simulatorRoot = getenv("SIMULATOR_ROOT");
372 if (simulatorRoot)
373 bundlePath = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s%@"), simulatorRoot, kSecSystemTrustStoreBundlePath);
374 #endif
375 if (!bundlePath)
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;
380 CFReleaseSafe(url);
381 CFReleaseSafe(bundlePath);
382 })
383
384 static CFURLRef SecSystemTrustStoreCopyResourceURL(CFStringRef resourceName,
385 CFStringRef resourceType, CFStringRef subDirName)
386 {
387 CFURLRef url = NULL;
388 CFBundleRef bundle = SecSystemTrustStoreGetBundle();
389 TestOTALog("SecSystemTrustStoreCopyResourceURL: bundle = %p\n", (void*)bundle);
390 if (bundle) {
391 url = CFBundleCopyResourceURL(bundle, resourceName,
392 resourceType, subDirName);
393 if (!url) {
394 secwarning("resource: %@.%@ in %@ not found", resourceName,
395 resourceType, subDirName);
396 }
397 }
398 if (!url) {
399 TestOTAResourceLog("SecSystemTrustStoreCopyResourceURL: unable to get URL!",
400 resourceName, resourceType, subDirName, url);
401 } else {
402 TestOTAResourceLog("SecSystemTrustStoreCopyResourceURL: got URL from bundle",
403 resourceName, resourceType, subDirName, url);
404 }
405 return url;
406 }
407
408 static CFDataRef SecSystemTrustStoreCopyResourceContents(CFStringRef resourceName,
409 CFStringRef resourceType, CFStringRef subDirName)
410 {
411 CFURLRef url = SecSystemTrustStoreCopyResourceURL(resourceName, resourceType, subDirName);
412 CFDataRef data = NULL;
413 if (url) {
414 SInt32 error;
415 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,
416 url, &data, NULL, NULL, &error)) {
417 secwarning("read: %ld", (long) error);
418 }
419 CFRelease(url);
420 }
421 TestOTALog("SecSystemTrustStoreCopyResourceContents: data = %p\n", data);
422 return data;
423 }
424
425 static CFPropertyListRef CFPropertyListCopyFromAsset(const char *ota_assets_path, CFStringRef asset)
426 {
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);
433
434 plist = CFPropertyListReadFromFile(url);
435 CFReleaseSafe(url);
436 CFReleaseSafe(filePath);
437 }
438
439 if (!plist) {
440 // no OTA asset file, so use the file in the system trust store bundle
441 xmlData = SecSystemTrustStoreCopyResourceContents(asset, CFSTR("plist"), NULL);
442
443 if (xmlData) {
444 plist = CFPropertyListCreateWithData(kCFAllocatorDefault, xmlData, kCFPropertyListImmutable, NULL, NULL);
445 CFRelease(xmlData);
446 }
447 }
448
449 return plist;
450 }
451
452 static CFSetRef CFSetCreateFromPropertyList(CFPropertyListRef plist)
453 {
454 CFSetRef result = NULL;
455
456 if (plist) {
457 CFMutableSetRef tempSet = NULL;
458 if (CFGetTypeID(plist) == CFArrayGetTypeID()) {
459 tempSet = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
460 if (NULL == tempSet) {
461 return result;
462 }
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);
468 }
469 }
470 else {
471 return result;
472 }
473
474 if (NULL != tempSet) {
475 result = tempSet;
476 }
477 }
478 return result;
479 }
480
481 static const char* InitOTADirectory(int* pAssetVersion)
482 {
483 TestOTALog("In InitOTADirectory\n");
484 const char* result = NULL;
485
486 char buffer[PATH_MAX];
487 DIR *dp;
488 struct dirent *ep;
489 int version = 0;
490 int current_version = 0;
491 int system_asset_version = 0;
492 CFIndex asset_number = 0;
493
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.
497
498 CFDataRef assetVersionData = SecSystemTrustStoreCopyResourceContents(CFSTR("AssetVersion"), CFSTR("plist"), NULL);
499 if (NULL != assetVersionData)
500 {
501 CFPropertyListFormat propFormat;
502 CFDictionaryRef versionPlist = CFPropertyListCreateWithData(kCFAllocatorDefault, assetVersionData, 0, &propFormat, NULL);
503 if (NULL != versionPlist && CFDictionaryGetTypeID() == CFGetTypeID(versionPlist))
504 {
505 CFNumberRef versionNumber = (CFNumberRef)CFDictionaryGetValue(versionPlist, (const void *)CFSTR("VersionNumber"));
506 if (NULL != versionNumber)
507 {
508 CFNumberGetValue(versionNumber, kCFNumberCFIndexType, &asset_number);
509 system_asset_version = (int)asset_number;
510 }
511 }
512 CFReleaseSafe(versionPlist);
513 CFReleaseSafe(assetVersionData);
514 }
515
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.
518
519 bool assetDirectoryExists = PathExists(kBaseAssetDirectory, NULL);
520 if (assetDirectoryExists)
521 {
522 TestOTALog("InitOTADirectory: \"%s\" exists\n", kBaseAssetDirectory);
523 dp = opendir (kBaseAssetDirectory);
524 if (NULL != dp)
525 {
526 TestOTALog("InitOTADirectory: opendir sucessfully open \"%s\"\n", kBaseAssetDirectory);
527 while ((ep = readdir(dp)))
528 {
529 TestOTALog("InitOTADirectory: processing name \"%s\"\n", ep->d_name);
530 if (strstr(ep->d_name, kVersionDirectoryNamePrefix))
531 {
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
539
540 TestOTALog("InitOTADirectory: version = %d\n", version);
541
542 if (current_version > 0)
543 {
544 if (version > current_version)
545 {
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))
551 {
552 rmrf(buffer);
553 }
554 current_version = version;
555 }
556 }
557 else
558 {
559 current_version = version;
560 }
561 }
562 }
563 closedir(dp);
564 }
565 else
566 {
567 TestOTALog("InitOTADirectory: opendir failed to open %s\n", kBaseAssetDirectory);
568 }
569 }
570 else
571 {
572 TestOTALog("InitOTADirectory: PathExists returned false for %s\n", kBaseAssetDirectory);
573 }
574
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)
579 {
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);
588 result = temp_str;
589 }
590 else
591 {
592 // The system asset number is newer than the OTA asset number
593 current_version = system_asset_version;
594 if (NULL != result)
595 {
596 free((void *)result);
597 }
598 result = NULL;
599 }
600
601 if (NULL != pAssetVersion)
602 {
603 *pAssetVersion = current_version;
604 }
605 return result;
606 }
607
608 static CF_RETURNS_RETAINED CFSetRef InitializeBlackList(const char* path_ptr)
609 {
610 CFPropertyListRef plist = CFPropertyListCopyFromAsset(path_ptr, CFSTR("Blocked"));
611 CFSetRef result = CFSetCreateFromPropertyList(plist);
612 CFReleaseSafe(plist);
613
614 return result;
615 }
616
617 static CF_RETURNS_RETAINED CFSetRef InitializeGrayList(const char* path_ptr)
618 {
619 CFPropertyListRef plist = CFPropertyListCopyFromAsset(path_ptr, CFSTR("GrayListedKeys"));
620 CFSetRef result = CFSetCreateFromPropertyList(plist);
621 CFReleaseSafe(plist);
622
623 return result;
624 }
625
626 static CF_RETURNS_RETAINED CFArrayRef InitializePinningList(const char* path_ptr)
627 {
628 CFPropertyListRef list = CFPropertyListCopyFromAsset(path_ptr, CFSTR("CertificatePinning"));
629
630 if (isArray(list)) {
631 return list;
632 } else {
633 CFReleaseNull(list);
634 return NULL;
635 }
636 }
637
638 static CF_RETURNS_RETAINED CFDictionaryRef InitializeAllowList(const char* path_ptr)
639 {
640 CFPropertyListRef allowList = CFPropertyListCopyFromAsset(path_ptr, CFSTR("Allowed"));
641
642 if (allowList && (CFGetTypeID(allowList) == CFDictionaryGetTypeID())) {
643 return allowList;
644 } else {
645 CFReleaseNull(allowList);
646 return NULL;
647 }
648 }
649
650 static CF_RETURNS_RETAINED CFArrayRef InitializeTrustedCTLogs(const char* path_ptr)
651 {
652 CFPropertyListRef trustedCTLogs = CFPropertyListCopyFromAsset(path_ptr, CFSTR("TrustedCTLogs"));
653
654 if (trustedCTLogs && (CFGetTypeID(trustedCTLogs) == CFArrayGetTypeID())) {
655 return trustedCTLogs;
656 } else {
657 CFReleaseNull(trustedCTLogs);
658 return NULL;
659 }
660 }
661
662 static CF_RETURNS_RETAINED CFDictionaryRef InitializeEVPolicyToAnchorDigestsTable(const char* path_ptr)
663 {
664 CFDictionaryRef result = NULL;
665 CFPropertyListRef evroots = CFPropertyListCopyFromAsset(path_ptr, CFSTR("EVRoots"));
666
667 if (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
671 20 byte digest. */
672 result = (CFDictionaryRef)evroots;
673 }
674 else {
675 secwarning("EVRoot.plist is wrong type.");
676 CFRelease(evroots);
677 }
678 }
679
680 return result;
681 }
682
683 static CFIndex InitializeValidSnapshotVersion(CFIndex *outFormat)
684 {
685 CFIndex validVersion = 0;
686 CFIndex validFormat = 0;
687 CFDataRef validVersionData = SecSystemTrustStoreCopyResourceContents(CFSTR("ValidUpdate"), CFSTR("plist"), NULL);
688 if (NULL != validVersionData)
689 {
690 CFPropertyListFormat propFormat;
691 CFDictionaryRef versionPlist = CFPropertyListCreateWithData(kCFAllocatorDefault, validVersionData, 0, &propFormat, NULL);
692 if (NULL != versionPlist && CFDictionaryGetTypeID() == CFGetTypeID(versionPlist))
693 {
694 CFNumberRef versionNumber = (CFNumberRef)CFDictionaryGetValue(versionPlist, (const void *)CFSTR("Version"));
695 if (NULL != versionNumber)
696 {
697 CFNumberGetValue(versionNumber, kCFNumberCFIndexType, &validVersion);
698 }
699 CFNumberRef formatNumber = (CFNumberRef)CFDictionaryGetValue(versionPlist, (const void *)CFSTR("Format"));
700 if (NULL != formatNumber)
701 {
702 CFNumberGetValue(formatNumber, kCFNumberCFIndexType, &validFormat);
703 }
704 }
705 CFReleaseSafe(versionPlist);
706 CFReleaseSafe(validVersionData);
707 }
708 if (outFormat) {
709 *outFormat = validFormat;
710 }
711 return validVersion;
712 }
713
714 static const char* InitializeValidSnapshotData(CFStringRef filename_str)
715 {
716 char *result = NULL;
717 const char *base_error_str = "could not get valid snapshot";
718
719 CFURLRef valid_url = SecSystemTrustStoreCopyResourceURL(filename_str, CFSTR("sqlite3"), NULL);
720 if (NULL == valid_url) {
721 secerror("%s", base_error_str);
722 } else {
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);
728 } else {
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;
733 }
734 }
735 if (NULL == valid_cstr) {
736 secerror("%s path as UTF8 string", base_error_str);
737 } else {
738 asprintf(&result, "%s", valid_cstr);
739 }
740 }
741 CFReleaseSafe(valid_str);
742 }
743 CFReleaseSafe(valid_url);
744 if (result && !PathExists(result, NULL)) {
745 free(result);
746 result = NULL;
747 }
748 return (const char*)result;
749 }
750
751 static const char* InitializeValidUpdateSnapshot()
752 {
753 return InitializeValidSnapshotData(CFSTR("update-full"));
754 }
755
756 static const char* InitializeValidDatabaseSnapshot()
757 {
758 return InitializeValidSnapshotData(CFSTR("valid"));
759 }
760
761 static void* MapFile(const char* path, int* out_fd, size_t* out_file_size)
762 {
763 void* result = NULL;
764 void* temp_result = NULL;
765 if (NULL == path || NULL == out_fd || NULL == out_file_size)
766 {
767 return result;
768 }
769
770 *out_fd = -1;
771 *out_file_size = 0;
772
773
774 *out_fd = open(path, O_RDONLY, 0666);
775
776 if (*out_fd == -1)
777 {
778 return result;
779 }
780
781 off_t fsize = lseek(*out_fd, 0, SEEK_END);
782 if (fsize == (off_t)-1)
783 {
784 return result;
785 }
786
787 if (fsize > (off_t)INT32_MAX)
788 {
789 close(*out_fd);
790 *out_fd = -1;
791 return result;
792 }
793
794 size_t malloc_size = (size_t)fsize;
795
796 temp_result = malloc(malloc_size);
797 if (NULL == temp_result)
798 {
799 close(*out_fd);
800 *out_fd = -1;
801 return result;
802 }
803
804 *out_file_size = malloc_size;
805
806 off_t total_read = 0;
807 while (total_read < fsize)
808 {
809 ssize_t bytes_read;
810
811 bytes_read = pread(*out_fd, temp_result, (size_t)(fsize - total_read), total_read);
812 if (bytes_read == -1)
813 {
814 free(temp_result);
815 temp_result = NULL;
816 close(*out_fd);
817 *out_fd = -1;
818 return result;
819 }
820 if (bytes_read == 0)
821 {
822 free(temp_result);
823 temp_result = NULL;
824 close(*out_fd);
825 *out_fd = -1;
826 return result;
827 }
828 total_read += bytes_read;
829 }
830
831 if (NULL != temp_result)
832 {
833 result = temp_result;
834 }
835
836 return result;
837 }
838
839 static void UnMapFile(void* mapped_data, size_t data_size)
840 {
841 #pragma unused(mapped_data, data_size)
842 if (NULL != mapped_data)
843 {
844 free((void *)mapped_data);
845 mapped_data = NULL;
846 }
847 }
848
849 static bool InitializeAnchorTable(const char* path_ptr, CFDictionaryRef* pLookupTable, const char** ppAnchorTable)
850 {
851
852 bool result = false;
853
854 if (NULL == pLookupTable || NULL == ppAnchorTable)
855 {
856 return result;
857 }
858
859 *pLookupTable = NULL;
860 *ppAnchorTable = NULL;;
861
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;
877
878 char* local_anchorTable = NULL;
879 size_t local_anchorTableSize = 0;
880 int local_anchorTable_fd = -1;
881
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.
886 //
887 // The anchor table file is mapped into memory. This SHOULD be OK as the
888 // size of the data is around 250K.
889 // ------------------------------------------------------------------------
890 dir_path = path_ptr;
891
892 if (NULL != dir_path)
893 {
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);
898
899 if (NULL != cert_index_file_data)
900 {
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);
904 }
905
906 free((void *)dir_path);
907 dir_path = NULL;
908 }
909
910 // Check to see if kAnchorTable was indeed set
911 if (NULL == local_anchorTable)
912 {
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");
918 }
919 table_data_url = SecSystemTrustStoreCopyResourceURL(CFSTR("certsTable"), CFSTR("data"), NULL);
920 if (!table_data_url) {
921 secerror("could not find certsTable");
922 }
923
924 if (NULL != table_data_url)
925 {
926 table_data_cstr_path = CFURLCopyFileSystemPath(table_data_url, kCFURLPOSIXPathStyle);
927 if (NULL != table_data_cstr_path)
928 {
929 memset(file_path_buffer, 0, PATH_MAX);
930 table_data_path = CFStringGetCStringPtr(table_data_cstr_path, kCFStringEncodingUTF8);
931 if (NULL == table_data_path)
932 {
933 if (CFStringGetCString(table_data_cstr_path, file_path_buffer, PATH_MAX, kCFStringEncodingUTF8))
934 {
935 table_data_path = file_path_buffer;
936 }
937 }
938 local_anchorTable = (char *)MapFile(table_data_path, &local_anchorTable_fd, &local_anchorTableSize);
939 CFReleaseSafe(table_data_cstr_path);
940 }
941 }
942 CFReleaseSafe(table_data_url);
943 }
944
945 if (NULL == local_anchorTable || NULL == cert_index_file_data)
946 {
947 // we are in trouble
948 if (NULL != local_anchorTable)
949 {
950 UnMapFile(local_anchorTable, local_anchorTableSize);
951 local_anchorTable = NULL;
952 local_anchorTableSize = 0;
953 }
954 CFReleaseSafe(cert_index_file_data);
955 return result;
956 }
957
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);
966
967 anchorLookupTable = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
968 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
969
970 for (index_offset = index_data_size; index_offset > 0; index_offset -= sizeof(index_record), pIndex++)
971 {
972 offset_int_value = pIndex->offset;
973
974 index_offset_value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &offset_int_value);
975 index_hash = CFDataCreate(kCFAllocatorDefault, pIndex->hash, CC_SHA1_DIGEST_LENGTH);
976
977 // see if the dictionary already has this key
978 release_offset = false;
979 offsets = (CFMutableArrayRef)CFDictionaryGetValue(anchorLookupTable, index_hash);
980 if (NULL == offsets)
981 {
982 offsets = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
983 release_offset = true;
984 }
985
986 // Add the offset
987 CFArrayAppendValue(offsets, index_offset_value);
988
989 // set the key value pair in the dictionary
990 CFDictionarySetValue(anchorLookupTable, index_hash, offsets);
991
992 CFRelease(index_offset_value);
993 CFRelease(index_hash);
994 if (release_offset)
995 {
996 CFRelease(offsets);
997 }
998 }
999
1000 CFRelease(cert_index_file_data);
1001
1002 if (NULL != anchorLookupTable && NULL != local_anchorTable)
1003 {
1004 *pLookupTable = anchorLookupTable;
1005 *ppAnchorTable = local_anchorTable;
1006 result = true;
1007 }
1008 else
1009 {
1010 CFReleaseSafe(anchorLookupTable);
1011 if (NULL != local_anchorTable)
1012 {
1013 UnMapFile(local_anchorTable, local_anchorTableSize);
1014 //munmap(kAnchorTable, local_anchorTableSize);
1015 local_anchorTable = NULL;
1016 local_anchorTableSize = 0;
1017 }
1018 }
1019
1020 return result;
1021 }
1022
1023 static void InitializeEscrowCertificates(const char* path_ptr, CFArrayRef *escrowRoots, CFArrayRef *escrowPCSRoots)
1024 {
1025 CFDataRef file_data = NULL;
1026
1027 const char* dir_path = path_ptr;
1028 if (NULL == dir_path)
1029 {
1030 file_data = SecSystemTrustStoreCopyResourceContents(CFSTR("AppleESCertificates"), CFSTR("plist"), NULL);
1031 }
1032 else
1033 {
1034 char buffer[1024];
1035 memset(buffer, 0, 1024);
1036 snprintf(buffer, 1024, "%s/AppleESCertificates.plist", dir_path);
1037 file_data = SecOTACopyFileContents(buffer);
1038 }
1039
1040 if (NULL != file_data)
1041 {
1042 CFPropertyListFormat propFormat;
1043 CFDictionaryRef certsDictionary = CFPropertyListCreateWithData(kCFAllocatorDefault, file_data, 0, &propFormat, NULL);
1044 if (NULL != certsDictionary && CFDictionaryGetTypeID() == CFGetTypeID((CFTypeRef)certsDictionary))
1045 {
1046 CFArrayRef certs = (CFArrayRef)CFDictionaryGetValue(certsDictionary, CFSTR("ProductionEscrowKey"));
1047 if (NULL != certs && CFArrayGetTypeID() == CFGetTypeID((CFTypeRef)certs) && CFArrayGetCount(certs) > 0)
1048 {
1049 *escrowRoots = CFArrayCreateCopy(kCFAllocatorDefault, certs);
1050 }
1051 CFArrayRef pcs_certs = (CFArrayRef)CFDictionaryGetValue(certsDictionary, CFSTR("ProductionPCSEscrowKey"));
1052 if (NULL != pcs_certs && CFArrayGetTypeID() == CFGetTypeID((CFTypeRef)pcs_certs) && CFArrayGetCount(pcs_certs) > 0)
1053 {
1054 *escrowPCSRoots = CFArrayCreateCopy(kCFAllocatorDefault, pcs_certs);
1055 }
1056 }
1057 CFReleaseSafe(certsDictionary);
1058 CFRelease(file_data);
1059 }
1060
1061 }
1062
1063
1064 static SecOTAPKIRef SecOTACreate()
1065 {
1066 TestOTALog("In SecOTACreate\n");
1067
1068 SecOTAPKIRef otapkiref = NULL;
1069
1070 otapkiref = CFTypeAllocate(SecOTAPKI, struct _OpaqueSecOTAPKI , kCFAllocatorDefault);
1071
1072 if (NULL == otapkiref)
1073 {
1074 return otapkiref;
1075 }
1076
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;
1095
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;
1101
1102 TestOTALog("SecOTACreate: asset_path = \"%s\"\n", (path_ptr) ? path_ptr : "");
1103 TestOTALog("SecOTACreate: asset_version = %d\n", asset_version);
1104
1105 // Get the set of black listed keys
1106 CFSetRef blackKeysSet = InitializeBlackList(path_ptr);
1107 if (NULL == blackKeysSet)
1108 {
1109 CFReleaseNull(otapkiref);
1110 return otapkiref;
1111 }
1112 otapkiref->_blackListSet = blackKeysSet;
1113
1114 // Get the set of gray listed keys
1115 CFSetRef grayKeysSet = InitializeGrayList(path_ptr);
1116 if (NULL == grayKeysSet)
1117 {
1118 CFReleaseNull(otapkiref);
1119 return otapkiref;
1120 }
1121 otapkiref->_grayListSet = grayKeysSet;
1122
1123 // Get the allow list dictionary
1124 // (now loaded lazily in SecOTAPKICopyAllowList)
1125
1126 // Get the trusted Certificate Transparency Logs
1127 otapkiref->_trustedCTLogs = InitializeTrustedCTLogs(path_ptr);
1128
1129 // Get the pinning list
1130 otapkiref->_pinningList = InitializePinningList(path_ptr);
1131
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;
1136
1137 // Get the valid update snapshot path (if it exists, NULL otherwise)
1138 otapkiref->_validUpdateSnapshot = InitializeValidUpdateSnapshot();
1139
1140 // Get the valid database snapshot path (if it exists, NULL otherwise)
1141 otapkiref->_validDatabaseSnapshot = InitializeValidDatabaseSnapshot();
1142
1143 CFArrayRef escrowCerts = NULL;
1144 CFArrayRef escrowPCSCerts = NULL;
1145 InitializeEscrowCertificates(path_ptr, &escrowCerts, &escrowPCSCerts);
1146 if (NULL == escrowCerts || NULL == escrowPCSCerts)
1147 {
1148 CFReleaseNull(escrowCerts);
1149 CFReleaseNull(escrowPCSCerts);
1150 CFReleaseNull(otapkiref);
1151 return otapkiref;
1152 }
1153 otapkiref->_escrowCertificates = escrowCerts;
1154 otapkiref->_escrowPCSCertificates = escrowPCSCerts;
1155
1156 // Get the mapping of EV Policy OIDs to Anchor digest
1157 CFDictionaryRef evOidToAnchorDigestMap = InitializeEVPolicyToAnchorDigestsTable(path_ptr);
1158 if (NULL == evOidToAnchorDigestMap)
1159 {
1160 CFReleaseNull(otapkiref);
1161 return otapkiref;
1162 }
1163 otapkiref->_evPolicyToAnchorMapping = evOidToAnchorDigestMap;
1164
1165 CFDictionaryRef anchorLookupTable = NULL;
1166 const char* anchorTablePtr = NULL;
1167
1168 if (!InitializeAnchorTable(path_ptr, &anchorLookupTable, &anchorTablePtr))
1169 {
1170 CFReleaseSafe(anchorLookupTable);
1171 if (anchorTablePtr) {
1172 free((void *)anchorTablePtr);
1173 }
1174 CFReleaseNull(otapkiref);
1175 return otapkiref;
1176 }
1177 otapkiref->_anchorLookupTable = anchorLookupTable;
1178 otapkiref->_anchorTable = anchorTablePtr;
1179 return otapkiref;
1180 }
1181
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;
1186
1187 SecOTAPKIRef SecOTAPKICopyCurrentOTAPKIRef()
1188 {
1189 __block SecOTAPKIRef result = NULL;
1190 dispatch_once(&kInitializeOTAPKI,
1191 ^{
1192 kOTAQueue = dispatch_queue_create(kOTAQueueLabel, NULL);
1193 kCurrentOTAPKIRef = SecOTACreate();
1194 });
1195
1196 dispatch_sync(kOTAQueue,
1197 ^{
1198 result = kCurrentOTAPKIRef;
1199 CFRetainSafe(result);
1200 });
1201 return result;
1202 }
1203
1204
1205 CFSetRef SecOTAPKICopyBlackListSet(SecOTAPKIRef otapkiRef)
1206 {
1207 CFSetRef result = NULL;
1208 if (NULL == otapkiRef)
1209 {
1210 return result;
1211 }
1212
1213 result = otapkiRef->_blackListSet;
1214 CFRetainSafe(result);
1215 return result;
1216 }
1217
1218
1219 CFSetRef SecOTAPKICopyGrayList(SecOTAPKIRef otapkiRef)
1220 {
1221 CFSetRef result = NULL;
1222 if (NULL == otapkiRef)
1223 {
1224 return result;
1225 }
1226
1227 result = otapkiRef->_grayListSet;
1228 CFRetainSafe(result);
1229 return result;
1230 }
1231
1232 CFDictionaryRef SecOTAPKICopyAllowList(SecOTAPKIRef otapkiRef)
1233 {
1234 CFDictionaryRef result = NULL;
1235 if (NULL == otapkiRef)
1236 {
1237 return result;
1238 }
1239
1240 result = otapkiRef->_allowList;
1241 if (!result) {
1242 result = InitializeAllowList(otapkiRef->_assetPath);
1243 otapkiRef->_allowList = result;
1244 }
1245
1246 CFRetainSafe(result);
1247 return result;
1248 }
1249
1250 CFArrayRef SecOTAPKICopyAllowListForAuthKeyID(SecOTAPKIRef otapkiRef, CFStringRef authKeyID)
1251 {
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")
1258 };
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;
1265 break;
1266 }
1267 }
1268 if (!hasAllowList || !otapkiRef) {
1269 return result;
1270 }
1271
1272 CFDictionaryRef allowListDict = SecOTAPKICopyAllowList(otapkiRef);
1273 if (!allowListDict) {
1274 return result;
1275 }
1276
1277 // return a retained copy of the allow list array (or NULL)
1278 result = CFDictionaryGetValue(allowListDict, authKeyID);
1279 CFRetainSafe(result);
1280 CFReleaseSafe(allowListDict);
1281 return result;
1282 }
1283
1284 CFArrayRef SecOTAPKICopyTrustedCTLogs(SecOTAPKIRef otapkiRef)
1285 {
1286 CFArrayRef result = NULL;
1287 if (NULL == otapkiRef)
1288 {
1289 return result;
1290 }
1291
1292 result = otapkiRef->_trustedCTLogs;
1293 CFRetainSafe(result);
1294 return result;
1295 }
1296
1297 CFArrayRef SecOTAPKICopyPinningList(SecOTAPKIRef otapkiRef) {
1298 CFArrayRef result = NULL;
1299 if (NULL == otapkiRef)
1300 {
1301 return result;
1302 }
1303
1304 result = otapkiRef->_pinningList;
1305 CFRetainSafe(result);
1306 return result;
1307 }
1308
1309
1310 /* Returns an array of certificate data (CFDataRef) */
1311 CFArrayRef SecOTAPKICopyEscrowCertificates(uint32_t escrowRootType, SecOTAPKIRef otapkiRef)
1312 {
1313 CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1314 if (NULL == otapkiRef) {
1315 return result;
1316 }
1317
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)));
1328 }
1329 break;
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
1337 };
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);
1347 }
1348 CFReleaseSafe(tmpCert);
1349 }
1350 }
1351 break;
1352 case kSecCertificateBaselinePCSEscrowRoot:
1353 case kSecCertificateProductionPCSEscrowRoot:
1354 if (otapkiRef->_escrowPCSCertificates) {
1355 CFArrayRef escrowPCSCerts = otapkiRef->_escrowPCSCertificates;
1356 CFArrayAppendArray(result, escrowPCSCerts, CFRangeMake(0, CFArrayGetCount(escrowPCSCerts)));
1357 }
1358 break;
1359 default:
1360 break;
1361 }
1362
1363 return result;
1364 }
1365
1366
1367 CFDictionaryRef SecOTAPKICopyEVPolicyToAnchorMapping(SecOTAPKIRef otapkiRef)
1368 {
1369 CFDictionaryRef result = NULL;
1370 if (NULL == otapkiRef)
1371 {
1372 return result;
1373 }
1374
1375 result = otapkiRef->_evPolicyToAnchorMapping;
1376 CFRetainSafe(result);
1377 return result;
1378 }
1379
1380
1381 CFDictionaryRef SecOTAPKICopyAnchorLookupTable(SecOTAPKIRef otapkiRef)
1382 {
1383 CFDictionaryRef result = NULL;
1384 if (NULL == otapkiRef)
1385 {
1386 return result;
1387 }
1388
1389 result = otapkiRef->_anchorLookupTable;
1390 CFRetainSafe(result);
1391 return result;
1392 }
1393
1394 const char* SecOTAPKIGetAnchorTable(SecOTAPKIRef otapkiRef)
1395 {
1396 const char* result = NULL;
1397 if (NULL == otapkiRef)
1398 {
1399 return result;
1400 }
1401
1402 result = otapkiRef->_anchorTable;
1403 return result;
1404 }
1405
1406 const char* SecOTAPKIGetValidUpdateSnapshot(SecOTAPKIRef otapkiRef)
1407 {
1408 const char* result = NULL;
1409 if (NULL == otapkiRef)
1410 {
1411 return result;
1412 }
1413
1414 result = otapkiRef->_validUpdateSnapshot;
1415 return result;
1416 }
1417
1418 const char* SecOTAPKIGetValidDatabaseSnapshot(SecOTAPKIRef otapkiRef)
1419 {
1420 const char* result = NULL;
1421 if (NULL == otapkiRef)
1422 {
1423 return result;
1424 }
1425
1426 result = otapkiRef->_validDatabaseSnapshot;
1427 return result;
1428 }
1429
1430 CFIndex SecOTAPKIGetValidSnapshotVersion(SecOTAPKIRef otapkiRef)
1431 {
1432 CFIndex result = 0;
1433 if (NULL == otapkiRef)
1434 {
1435 return result;
1436 }
1437
1438 result = otapkiRef->_validSnapshotVersion;
1439 return result;
1440 }
1441
1442 CFIndex SecOTAPKIGetValidSnapshotFormat(SecOTAPKIRef otapkiRef)
1443 {
1444 CFIndex result = 0;
1445 if (NULL == otapkiRef)
1446 {
1447 return result;
1448 }
1449
1450 result = otapkiRef->_validSnapshotFormat;
1451 return result;
1452 }
1453
1454 int SecOTAPKIGetAssetVersion(SecOTAPKIRef otapkiRef)
1455 {
1456 int result = 0;
1457 if (NULL == otapkiRef)
1458 {
1459 return result;
1460 }
1461
1462 result = otapkiRef->_assetVersion;
1463 return result;
1464 }
1465
1466 void SecOTAPKIRefreshData()
1467 {
1468 TestOTALog("In SecOTAPKIRefreshData\n");
1469 SecOTAPKIRef new_otaPKRef = SecOTACreate();
1470 dispatch_sync(kOTAQueue,
1471 ^{
1472 CFReleaseSafe(kCurrentOTAPKIRef);
1473 kCurrentOTAPKIRef = new_otaPKRef;
1474 });
1475 }
1476
1477 /* Returns an array of certificate data (CFDataRef) */
1478 CFArrayRef SecOTAPKICopyCurrentEscrowCertificates(uint32_t escrowRootType, CFErrorRef* error)
1479 {
1480 CFArrayRef result = NULL;
1481
1482 SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
1483 if (NULL == otapkiref)
1484 {
1485 SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef"));
1486 return result;
1487 }
1488
1489 result = SecOTAPKICopyEscrowCertificates(escrowRootType, otapkiref);
1490 CFRelease(otapkiref);
1491
1492 if (NULL == result)
1493 {
1494 SecError(errSecInternal, error, CFSTR("Could not get escrow certificates from the current OTAPKIRef"));
1495 }
1496 return result;
1497 }
1498
1499 int SecOTAPKIGetCurrentAssetVersion(CFErrorRef* error)
1500 {
1501 int result = 0;
1502
1503 SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef();
1504 if (NULL == otapkiref)
1505 {
1506 SecError(errSecInternal, error, CFSTR("Unable to get the current OTAPKIRef"));
1507 return result;
1508 }
1509
1510 result = otapkiref->_assetVersion;
1511 return result;
1512 }
1513
1514 int SecOTAPKISignalNewAsset(CFErrorRef* error)
1515 {
1516 TestOTALog("SecOTAPKISignalNewAsset has been called!\n");
1517 SecOTAPKIRefreshData();
1518 return 1;
1519 }