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