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