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