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 56static 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 80static const char* kBaseAssertDirectory = "/var/OTAPKI/Assets"; 81#else 82static const char* kBaseAssertDirectory = "/var/Keychains/Assets"; 83#endif 84 85static const char* kVersionDirectoryNamePrefix = "Version_"; 86static const char* kNumberString = "%d"; 87 88struct index_record 89{ 90 unsigned char hash[CC_SHA1_DIGEST_LENGTH]; 91 uint32_t offset; 92}; 93typedef struct index_record index_record; 94 95 96struct _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 108CFGiblisFor(SecOTAPKI) 109 110static 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 116static 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 130static 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 184badFile: 185 if (fd != -1) 186 { 187 close(fd); 188 } 189 190 if (data) 191 { 192 CFRelease(data); 193 } 194 195 return NULL; 196} 197 198static 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 285static 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 291static 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 305static 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 417static 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 485static 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 553static 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 607static 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 685static 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 695static 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 857static 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 895static 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 980static dispatch_once_t kInitializeOTAPKI = 0; 981static const char* kOTAQueueLabel = "com.apple.security.OTAPKIQueue"; 982static dispatch_queue_t kOTAQueue; 983static SecOTAPKIRef kCurrentOTAPKIRef = NULL; 984 985SecOTAPKIRef 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 1003CFSetRef 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 1017CFSetRef 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 1030CFArrayRef 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 1044CFDictionaryRef 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 1058CFDictionaryRef 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 1071const 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 1083int 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 1095void 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 1106CFArrayRef 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 1127int 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 1142int SecOTAPKISignalNewAsset(CFErrorRef* error) 1143{ 1144 TestOTALog("SecOTAPKISignalNewAsset has been called!\n"); 1145 SecOTAPKIRefreshData(); 1146 return 1; 1147} 1148