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