1/*
2 * Copyright (c) 2002-2010,2012-2013 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
24#include "SecTrust.h"
25#include "SecTrustPriv.h"
26#include "Trust.h"
27#include <security_keychain/SecTrustSettingsPriv.h>
28#include "SecBridge.h"
29#include "SecInternal.h"
30#include "SecInternalP.h"
31#include "SecTrustSettings.h"
32#include "SecCertificatePriv.h"
33#include "SecCertificateP.h"
34#include "SecCertificatePrivP.h"
35#include <security_utilities/cfutilities.h>
36#include <security_utilities/cfmunge.h>
37#include <CoreFoundation/CoreFoundation.h>
38
39// forward declarations
40CFArrayRef SecTrustCopyDetails(SecTrustRef trust);
41static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix);
42static void SecTrustCheckException(const void *key, const void *value, void *context);
43
44typedef struct SecTrustCheckExceptionContext {
45	CFDictionaryRef exception;
46	bool exceptionNotFound;
47} SecTrustCheckExceptionContext;
48
49// public trust result constants
50CFTypeRef kSecTrustEvaluationDate           = CFSTR("TrustEvaluationDate");
51CFTypeRef kSecTrustExtendedValidation       = CFSTR("TrustExtendedValidation");
52CFTypeRef kSecTrustOrganizationName         = CFSTR("Organization");
53CFTypeRef kSecTrustResultValue              = CFSTR("TrustResultValue");
54CFTypeRef kSecTrustRevocationChecked        = CFSTR("TrustRevocationChecked");
55CFTypeRef kSecTrustRevocationValidUntilDate = CFSTR("TrustExpirationDate");
56CFTypeRef kSecTrustResultDetails            = CFSTR("TrustResultDetails");
57
58//
59// CF boilerplate
60//
61CFTypeID SecTrustGetTypeID(void)
62{
63	BEGIN_SECAPI
64
65	return gTypes().Trust.typeID;
66
67	END_SECAPI1(_kCFRuntimeNotATypeID)
68}
69
70
71//
72// Sec* API bridge functions
73//
74OSStatus SecTrustCreateWithCertificates(
75	CFTypeRef certificates,
76	CFTypeRef policies,
77	SecTrustRef *trustRef)
78{
79	BEGIN_SECAPI
80	Required(trustRef);
81	*trustRef = (new Trust(certificates, policies))->handle();
82	END_SECAPI
83}
84
85OSStatus
86SecTrustSetPolicies(SecTrustRef trustRef, CFTypeRef policies)
87{
88	BEGIN_SECAPI
89	Trust::required(trustRef)->policies(policies);
90	END_SECAPI
91}
92
93OSStatus
94SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options)
95{
96	BEGIN_SECAPI
97	CSSM_APPLE_TP_ACTION_DATA actionData = {
98		CSSM_APPLE_TP_ACTION_VERSION,
99		(CSSM_APPLE_TP_ACTION_FLAGS)options
100	};
101	Trust *trust = Trust::required(trustRef);
102	CFDataRef actionDataRef = CFDataCreate(NULL,
103		(const UInt8 *)&actionData,
104		(CFIndex)sizeof(CSSM_APPLE_TP_ACTION_DATA));
105	trust->action(CSSM_TP_ACTION_DEFAULT);
106	trust->actionData(actionDataRef);
107	if (actionDataRef) CFRelease(actionDataRef);
108	END_SECAPI
109}
110
111OSStatus SecTrustSetParameters(
112    SecTrustRef trustRef,
113    CSSM_TP_ACTION action,
114    CFDataRef actionData)
115{
116    BEGIN_SECAPI
117    Trust *trust = Trust::required(trustRef);
118    trust->action(action);
119    trust->actionData(actionData);
120    END_SECAPI
121}
122
123
124OSStatus SecTrustSetAnchorCertificates(SecTrustRef trust, CFArrayRef anchorCertificates)
125{
126    BEGIN_SECAPI
127    Trust::required(trust)->anchors(anchorCertificates);
128    END_SECAPI
129}
130
131OSStatus SecTrustSetAnchorCertificatesOnly(SecTrustRef trust, Boolean anchorCertificatesOnly)
132{
133    BEGIN_SECAPI
134    Trust::AnchorPolicy policy = (anchorCertificatesOnly) ? Trust::useAnchorsOnly : Trust::useAnchorsAndBuiltIns;
135    Trust::required(trust)->anchorPolicy(policy);
136    END_SECAPI
137}
138
139OSStatus SecTrustSetKeychains(SecTrustRef trust, CFTypeRef keychainOrArray)
140{
141	BEGIN_SECAPI
142		StorageManager::KeychainList keychains;
143	// avoid unnecessary global initializations if an empty array is passed in
144	if (!( (keychainOrArray != NULL) &&
145				(CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) &&
146				(CFArrayGetCount((CFArrayRef)keychainOrArray) == 0) )) {
147		globals().storageManager.optionalSearchList(keychainOrArray, keychains);
148	}
149	Trust::required(trust)->searchLibs(keychains);
150	END_SECAPI
151}
152
153
154OSStatus SecTrustSetVerifyDate(SecTrustRef trust, CFDateRef verifyDate)
155{
156    BEGIN_SECAPI
157    Trust::required(trust)->time(verifyDate);
158    END_SECAPI
159}
160
161
162CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust)
163{
164	CFAbsoluteTime verifyTime = 0;
165	OSStatus __secapiresult = errSecSuccess;
166	try {
167		CFRef<CFDateRef> verifyDate = Trust::required(trust)->time();
168		verifyTime = CFDateGetAbsoluteTime(verifyDate);
169	}
170	catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
171	catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
172	catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
173	catch (...) { __secapiresult=errSecInternalComponent; }
174	return verifyTime;
175}
176
177
178OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *resultP)
179{
180	SecTrustResultType trustResult = kSecTrustResultInvalid;
181	CFArrayRef exceptions = NULL;
182	OSStatus __secapiresult = errSecSuccess;
183	try {
184		Trust *trustObj = Trust::required(trust);
185		trustObj->evaluate();
186		trustResult = trustObj->result();
187		exceptions = trustObj->exceptions();
188	}
189	catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
190	catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
191	catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
192	catch (...) { __secapiresult=errSecInternalComponent; }
193
194	if (__secapiresult) {
195		return __secapiresult;
196	}
197
198	/* post-process trust result based on exceptions */
199	if (trustResult == kSecTrustResultUnspecified) {
200		/* If leaf is in exceptions -> proceed, otherwise unspecified. */
201		if (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
202			trustResult = kSecTrustResultProceed;
203	}
204	else if (trustResult == kSecTrustResultRecoverableTrustFailure && exceptions) {
205		/* If we have exceptions get details and match to exceptions. */
206		CFArrayRef details = SecTrustCopyDetails(trust);
207		if (details) {
208			CFIndex pathLength = CFArrayGetCount(details);
209			struct SecTrustCheckExceptionContext context = {};
210			CFIndex ix;
211			for (ix = 0; ix < pathLength; ++ix) {
212				CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
213			//	if ((ix == 0) && CFDictionaryContainsKey(detail, kSecPolicyCheckBlackListedLeaf))
214			//		trustResult = kSecTrustResultFatalTrustFailure;
215				context.exception = SecTrustGetExceptionForCertificateAtIndex(trust, ix);
216				CFDictionaryApplyFunction(detail, SecTrustCheckException, &context);
217				if (context.exceptionNotFound) {
218					break;
219				}
220			}
221			if (!context.exceptionNotFound)
222				trustResult = kSecTrustResultProceed;
223		}
224	}
225
226
227	secdebug("SecTrustEvaluate", "SecTrustEvaluate trust result = %d", (int)trustResult);
228	if (resultP) {
229		*resultP = trustResult;
230	}
231	return __secapiresult;
232}
233
234OSStatus SecTrustEvaluateAsync(SecTrustRef trust,
235	dispatch_queue_t queue, SecTrustCallback result)
236{
237	BEGIN_SECAPI
238	dispatch_async(queue, ^{
239		try {
240			Trust *trustObj = Trust::required(trust);
241			trustObj->evaluate();
242			SecTrustResultType trustResult = trustObj->result();
243			result(trust, trustResult);
244		}
245		catch (...) {
246			result(trust, kSecTrustResultInvalid);
247		};
248	});
249	END_SECAPI
250}
251
252//
253// Construct the "official" result evidence and return it
254//
255OSStatus SecTrustGetResult(
256    SecTrustRef trustRef,
257    SecTrustResultType *result,
258	CFArrayRef *certChain, CSSM_TP_APPLE_EVIDENCE_INFO **statusChain)
259{
260    BEGIN_SECAPI
261    Trust *trust = Trust::required(trustRef);
262    if (result)
263        *result = trust->result();
264    if (certChain && statusChain)
265        trust->buildEvidence(*certChain, TPEvidenceInfo::overlayVar(*statusChain));
266    END_SECAPI
267}
268
269//
270// Retrieve result of trust evaluation only
271//
272OSStatus SecTrustGetTrustResult(SecTrustRef trustRef,
273	SecTrustResultType *result)
274{
275    BEGIN_SECAPI
276    Trust *trust = Trust::required(trustRef);
277    if (result) *result = trust->result();
278    END_SECAPI
279}
280
281//
282// Retrieve extended validation trust results
283//
284OSStatus SecTrustCopyExtendedResult(SecTrustRef trust, CFDictionaryRef *result)
285{
286    BEGIN_SECAPI
287	Trust *trustObj = Trust::required(trust);
288	if (result == nil)
289		return errSecParam;
290	trustObj->extendedResult(*result);
291    END_SECAPI
292}
293
294//
295// Retrieve CSSM-level information for those who want to dig down
296//
297OSStatus SecTrustGetCssmResult(SecTrustRef trust, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR *result)
298{
299    BEGIN_SECAPI
300    Required(result) = Trust::required(trust)->cssmResult();
301    END_SECAPI
302}
303
304//
305// Retrieve CSSM_LEVEL TP return code
306//
307OSStatus SecTrustGetCssmResultCode(SecTrustRef trustRef, OSStatus *result)
308{
309	BEGIN_SECAPI
310		Trust *trust = Trust::required(trustRef);
311	if (trust->result() == kSecTrustResultInvalid)
312		return errSecParam;
313	else
314		Required(result) = trust->cssmResultCode();
315	END_SECAPI
316}
317
318OSStatus SecTrustGetTPHandle(SecTrustRef trust, CSSM_TP_HANDLE *handle)
319{
320	BEGIN_SECAPI
321		Required(handle) = Trust::required(trust)->getTPHandle();
322	END_SECAPI
323}
324
325OSStatus SecTrustCopyPolicies(SecTrustRef trust, CFArrayRef *policies)
326{
327	BEGIN_SECAPI
328		CFArrayRef currentPolicies = Trust::required(trust)->policies();
329	if (currentPolicies != NULL)
330	{
331		CFRetain(currentPolicies);
332	}
333
334	Required(policies) = currentPolicies;
335	END_SECAPI
336}
337
338OSStatus SecTrustSetNetworkFetchAllowed(SecTrustRef trust, Boolean allowFetch)
339{
340	BEGIN_SECAPI
341	Trust *trustObj = Trust::required(trust);
342	Trust::NetworkPolicy netPolicy = (allowFetch) ?
343		Trust::useNetworkEnabled : Trust::useNetworkDisabled;
344	trustObj->networkPolicy(netPolicy);
345	END_SECAPI
346}
347
348OSStatus SecTrustGetNetworkFetchAllowed(SecTrustRef trust, Boolean *allowFetch)
349{
350	BEGIN_SECAPI
351	Boolean allowed = false;
352	Trust *trustObj = Trust::required(trust);
353	Trust::NetworkPolicy netPolicy = trustObj->networkPolicy();
354	if (netPolicy == Trust::useNetworkDefault) {
355		// network fetch is enabled by default for SSL only
356		allowed = trustObj->policySpecified(trustObj->policies(), CSSMOID_APPLE_TP_SSL);
357	} else {
358		// caller has explicitly set the network policy
359		allowed = (netPolicy == Trust::useNetworkEnabled);
360	}
361	Required(allowFetch) = allowed;
362	END_SECAPI
363}
364
365OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef responseData)
366{
367	BEGIN_SECAPI
368	Trust::required(trust)->responses(responseData);
369	END_SECAPI
370}
371
372OSStatus SecTrustCopyCustomAnchorCertificates(SecTrustRef trust, CFArrayRef *anchorCertificates)
373{
374	BEGIN_SECAPI
375	CFArrayRef customAnchors = Trust::required(trust)->anchors();
376	Required(anchorCertificates) = (customAnchors) ?
377		(const CFArrayRef)CFRetain(customAnchors) : (const CFArrayRef)NULL;
378	END_SECAPI
379}
380
381//
382// Get the user's default anchor certificate set
383//
384OSStatus SecTrustCopyAnchorCertificates(CFArrayRef *anchorCertificates)
385{
386	BEGIN_SECAPI
387
388	return SecTrustSettingsCopyUnrestrictedRoots(
389			true, true, true,		/* all domains */
390			anchorCertificates);
391
392	END_SECAPI
393}
394
395/* new in 10.6 */
396SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
397{
398	SecKeyRef pubKey = NULL;
399	CFArrayRef certChain = NULL;
400	CFArrayRef evidenceChain = NULL;
401	CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
402	OSStatus __secapiresult = errSecSuccess;
403	try {
404		Trust *trustObj = Trust::required(trust);
405		if (trustObj->result() == kSecTrustResultInvalid) {
406			// Trust hasn't been evaluated; attempt to retrieve public key from leaf.
407			SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, 0);
408			__secapiresult = SecCertificateCopyPublicKey(cert, &pubKey);
409			if (pubKey) {
410				return pubKey;
411			}
412			// Otherwise, we must evaluate first.
413			trustObj->evaluate();
414			if (trustObj->result() == kSecTrustResultInvalid) {
415				MacOSError::throwMe(errSecTrustNotAvailable);
416			}
417		}
418		if (trustObj->evidence() == nil) {
419			trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain));
420		}
421		evidenceChain = trustObj->evidence();
422	}
423	catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
424	catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
425	catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
426	catch (...) { __secapiresult=errSecInternalComponent; }
427
428	if (certChain)
429		CFRelease(certChain);
430
431	if (evidenceChain) {
432		if (CFArrayGetCount(evidenceChain) > 0) {
433			SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(evidenceChain, 0);
434			__secapiresult = SecCertificateCopyPublicKey(cert, &pubKey);
435		}
436		// do not release evidenceChain, as it is owned by the trust object.
437	}
438	return pubKey;
439}
440
441/* new in 10.6 */
442CFIndex SecTrustGetCertificateCount(SecTrustRef trust)
443{
444	CFIndex chainLen = 0;
445	CFArrayRef certChain = NULL;
446	CFArrayRef evidenceChain = NULL;
447	CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
448    OSStatus __secapiresult = errSecSuccess;
449	try {
450		Trust *trustObj = Trust::required(trust);
451		if (trustObj->result() == kSecTrustResultInvalid) {
452			trustObj->evaluate();
453			if (trustObj->result() == kSecTrustResultInvalid)
454				MacOSError::throwMe(errSecTrustNotAvailable);
455		}
456		if (trustObj->evidence() == nil)
457			trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain));
458		evidenceChain = trustObj->evidence();
459	}
460	catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
461	catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
462	catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
463	catch (...) { __secapiresult=errSecInternalComponent; }
464
465	if (certChain)
466		CFRelease(certChain);
467
468	if (evidenceChain)
469		chainLen = CFArrayGetCount(evidenceChain); // don't release, trust object owns it.
470
471    return chainLen;
472}
473
474/* new in 10.6 */
475SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust, CFIndex ix)
476{
477	SecCertificateRef certificate = NULL;
478	CFArrayRef certChain = NULL;
479	CFArrayRef evidenceChain = NULL;
480	CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
481    OSStatus __secapiresult = errSecSuccess;
482	try {
483		Trust *trustObj = Trust::required(trust);
484		if (trustObj->result() == kSecTrustResultInvalid) {
485			// If caller is asking for the leaf, we can return it without
486			// having to evaluate the entire chain. Note that we don't retain
487			// the cert as it's owned by the trust and this is a 'Get' API.
488			if (ix == 0) {
489				CFArrayRef certs = trustObj->certificates();
490				if (certs && (CFArrayGetCount(certs) > 0)) {
491					certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certs, 0);
492					if (certificate) {
493						return certificate;
494					}
495				}
496			}
497			// Otherwise, we must evaluate first.
498			trustObj->evaluate();
499			if (trustObj->result() == kSecTrustResultInvalid) {
500				MacOSError::throwMe(errSecTrustNotAvailable);
501			}
502		}
503		if (trustObj->evidence() == nil) {
504			trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain));
505		}
506		evidenceChain = trustObj->evidence();
507	}
508	catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
509	catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
510	catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
511	catch (...) { __secapiresult=errSecInternalComponent; }
512
513	if (certChain)
514		CFRelease(certChain);
515
516	if (evidenceChain) {
517		if (ix < CFArrayGetCount(evidenceChain)) {
518			certificate = (SecCertificateRef) CFArrayGetValueAtIndex(evidenceChain, ix);
519			// note: we do not retain this certificate. The assumption here is
520			// that the certificate is retained by the trust object, so it is
521			// valid unil the trust is released (or until re-evaluated.)
522			// also note: we do not release the evidenceChain, as it is owned
523			// by the trust object.
524		}
525	}
526	return certificate;
527}
528
529
530static CFStringRef kSecCertificateDetailSHA1Digest = CFSTR("SHA1Digest");
531static CFStringRef kSecCertificateDetailStatusCodes = CFSTR("StatusCodes");
532
533static void
534_AppendStatusCode(CFMutableArrayRef array, OSStatus statusCode)
535{
536	if (!array)
537		return;
538	SInt32 num = statusCode;
539	CFNumberRef numRef = CFNumberCreate(NULL, kCFNumberSInt32Type, &num);
540	if (!numRef)
541		return;
542	CFArrayAppendValue(array, numRef);
543	CFRelease(numRef);
544}
545
546CFArrayRef SecTrustCopyDetails(SecTrustRef trust)
547{
548	// This function returns an array of dictionaries, one per certificate,
549	// holding status info for each certificate in the evaluated chain.
550	//
551	CFIndex count, chainLen = 0;
552	CFArrayRef certChain = NULL;
553	CFMutableArrayRef details = NULL;
554	CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
555    OSStatus __secapiresult = errSecSuccess;
556	try {
557		Trust *trustObj = Trust::required(trust);
558		if (trustObj->result() == kSecTrustResultInvalid) {
559			trustObj->evaluate();
560			if (trustObj->result() == kSecTrustResultInvalid)
561				MacOSError::throwMe(errSecTrustNotAvailable);
562		}
563		trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain));
564	}
565	catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
566	catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
567	catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
568	catch (...) { __secapiresult=errSecInternalComponent; }
569
570	if (certChain) {
571		chainLen = CFArrayGetCount(certChain);
572		CFRelease(certChain);
573	}
574	if (statusChain) {
575		details = CFArrayCreateMutable(NULL, chainLen, &kCFTypeArrayCallBacks);
576		for (count = 0; count < chainLen; count++) {
577			CFMutableDictionaryRef certDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
578				0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
579			CFMutableArrayRef statusCodes = CFArrayCreateMutable(kCFAllocatorDefault,
580				0, &kCFTypeArrayCallBacks);
581			CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &statusChain[count];
582			CSSM_TP_APPLE_CERT_STATUS statBits = evInfo->StatusBits;
583
584			// translate status bits
585			if (statBits & CSSM_CERT_STATUS_EXPIRED)
586				_AppendStatusCode(statusCodes, errSecCertificateExpired);
587			if (statBits & CSSM_CERT_STATUS_NOT_VALID_YET)
588				_AppendStatusCode(statusCodes, errSecCertificateNotValidYet);
589			if (statBits & CSSM_CERT_STATUS_TRUST_SETTINGS_DENY)
590				_AppendStatusCode(statusCodes, errSecTrustSettingDeny);
591
592			// translate status codes
593			unsigned int i;
594			for (i = 0; i < evInfo->NumStatusCodes; i++) {
595				CSSM_RETURN scode = evInfo->StatusCodes[i];
596				_AppendStatusCode(statusCodes, (OSStatus)scode);
597			}
598
599			CFDictionarySetValue(certDict, kSecCertificateDetailStatusCodes, statusCodes);
600			CFRelease(statusCodes);
601			CFArrayAppendValue(details, certDict);
602			CFRelease(certDict);
603		}
604	}
605	return details;
606}
607
608static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix)
609{
610	CFArrayRef exceptions = NULL;
611    OSStatus __secapiresult = errSecSuccess;
612	try {
613		exceptions = Trust::required(trust)->exceptions();
614	}
615	catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
616	catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
617	catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
618	catch (...) { __secapiresult=errSecInternalComponent; }
619
620	if (!exceptions || ix >= CFArrayGetCount(exceptions))
621		return NULL;
622	CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
623	if (CFGetTypeID(exception) != CFDictionaryGetTypeID())
624		return NULL;
625
626	SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
627	if (!certificate)
628		return NULL;
629
630	/* If the exception contains the current certificate's sha1Digest in the
631	   kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
632	CFDataRef sha1Digest = SecCertificateGetSHA1Digest(certificate);
633	CFTypeRef digestValue = CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest);
634	if (!digestValue || !CFEqual(sha1Digest, digestValue))
635		exception = NULL;
636
637	return exception;
638}
639
640static void SecTrustCheckException(const void *key, const void *value, void *context)
641{
642	struct SecTrustCheckExceptionContext *cec = (struct SecTrustCheckExceptionContext *)context;
643	if (cec->exception) {
644		CFTypeRef exceptionValue = CFDictionaryGetValue(cec->exception, key);
645		if (!exceptionValue || !CFEqual(value, exceptionValue)) {
646			cec->exceptionNotFound = true;
647		}
648	} else {
649		cec->exceptionNotFound = true;
650	}
651}
652
653/* new in 10.9 */
654CFDataRef SecTrustCopyExceptions(SecTrustRef trust)
655{
656	CFArrayRef details = SecTrustCopyDetails(trust);
657	CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
658	CFMutableArrayRef exceptions = CFArrayCreateMutable(kCFAllocatorDefault,
659			pathLength, &kCFTypeArrayCallBacks);
660	CFIndex ix;
661	for (ix = 0; ix < pathLength; ++ix) {
662		CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
663		CFIndex detailCount = CFDictionaryGetCount(detail);
664		CFMutableDictionaryRef exception;
665		if (ix == 0 || detailCount > 0) {
666			exception = CFDictionaryCreateMutableCopy(kCFAllocatorDefault,
667				detailCount + 1, detail);
668			SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
669			CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
670			if (digest) {
671				CFDictionaryAddValue(exception, kSecCertificateDetailSHA1Digest, digest);
672			}
673		} else {
674			/* Add empty exception dictionaries for non leaf certs which have no exceptions
675			 * to save space.
676			 */
677			exception = (CFMutableDictionaryRef)CFDictionaryCreate(kCFAllocatorDefault,
678				NULL, NULL, 0,
679				&kCFTypeDictionaryKeyCallBacks,
680				&kCFTypeDictionaryValueCallBacks);
681		}
682		CFArrayAppendValue(exceptions, exception);
683		CFReleaseNull(exception);
684	}
685	CFReleaseSafe(details);
686
687	/* Remove any trailing empty dictionaries to save even more space (we skip the leaf
688	   since it will never be empty). */
689	for (ix = pathLength; ix-- > 1;) {
690		CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
691		if (CFDictionaryGetCount(exception) == 0) {
692			CFArrayRemoveValueAtIndex(exceptions, ix);
693		} else {
694			break;
695		}
696	}
697
698	CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
699			exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
700	CFRelease(exceptions);
701
702	return encodedExceptions;
703}
704
705/* new in 10.9 */
706bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions)
707{
708	CFArrayRef exceptions;
709	exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault,
710		encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
711	if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
712		CFRelease(exceptions);
713		exceptions = NULL;
714	}
715
716	OSStatus __secapiresult = errSecSuccess;
717	try {
718		Trust::required(trust)->exceptions(exceptions);
719	}
720	catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
721	catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
722	catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
723	catch (...) { __secapiresult=errSecInternalComponent; }
724
725	/* If there is a valid exception entry for our current leaf we're golden. */
726	if (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
727		return true;
728
729	/* The passed in exceptions didn't match our current leaf, so we discard it. */
730	try {
731		Trust::required(trust)->exceptions(NULL);
732		__secapiresult = errSecSuccess;
733	}
734	catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
735	catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
736	catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
737	catch (...) { __secapiresult=errSecInternalComponent; }
738
739	return false;
740}
741
742/* new in 10.9 */
743CFDictionaryRef
744SecTrustCopyResult(SecTrustRef trust)
745{
746	CFDictionaryRef result = NULL;
747	try {
748		result = Trust::required(trust)->results();
749		// merge details into result
750		CFArrayRef details = SecTrustCopyDetails(trust);
751		if (details) {
752			CFDictionarySetValue((CFMutableDictionaryRef)result,
753				kSecTrustResultDetails, details);
754			CFRelease(details);
755		}
756	}
757	catch (...) {
758		if (result) {
759			CFRelease(result);
760			result = NULL;
761		}
762	}
763	return result;
764}
765
766/* new in 10.7 */
767CFArrayRef
768SecTrustCopyProperties(SecTrustRef trust)
769{
770	/* can't use SECAPI macros, since this function does not return OSStatus */
771	CFArrayRef result = NULL;
772	try {
773		result = Trust::required(trust)->properties();
774	}
775	catch (...) {
776		if (result) {
777			CFRelease(result);
778			result = NULL;
779		}
780	}
781	return result;
782}
783
784
785/* deprecated in 10.5 */
786OSStatus SecTrustGetCSSMAnchorCertificates(const CSSM_DATA **cssmAnchors,
787	uint32 *cssmAnchorCount)
788{
789	BEGIN_SECAPI
790	CertGroup certs;
791	Trust::gStore().getCssmRootCertificates(certs);
792	Required(cssmAnchors) = certs.blobCerts();
793	Required(cssmAnchorCount) = certs.count();
794	END_SECAPI
795}
796
797
798//
799// Get and set user trust settings. Deprecated in 10.5.
800// User Trust getter, deprecated, works as it always has.
801//
802OSStatus SecTrustGetUserTrust(SecCertificateRef certificate,
803    SecPolicyRef policy, SecTrustUserSetting *trustSetting)
804{
805	BEGIN_SECAPI
806	StorageManager::KeychainList searchList;
807	globals().storageManager.getSearchList(searchList);
808	Required(trustSetting) = Trust::gStore().find(
809		Certificate::required(certificate),
810		Policy::required(policy),
811		searchList);
812	END_SECAPI
813}
814
815//
816// The public setter, also deprecated; it maps to the appropriate
817// Trust Settings call if possible, else throws errSecUnimplemented.
818//
819OSStatus SecTrustSetUserTrust(SecCertificateRef certificate,
820    SecPolicyRef policy, SecTrustUserSetting trustSetting)
821{
822	SecTrustSettingsResult tsResult = kSecTrustSettingsResultInvalid;
823	OSStatus ortn;
824	Boolean isRoot;
825
826	Policy::required(policy);
827	switch(trustSetting) {
828		case kSecTrustResultProceed:
829			/* different SecTrustSettingsResult depending in root-ness */
830			ortn = SecCertificateIsSelfSigned(certificate, &isRoot);
831			if(ortn) {
832				return ortn;
833			}
834			if(isRoot) {
835				tsResult = kSecTrustSettingsResultTrustRoot;
836			}
837			else {
838				tsResult = kSecTrustSettingsResultTrustAsRoot;
839			}
840			break;
841		case kSecTrustResultDeny:
842			tsResult = kSecTrustSettingsResultDeny;
843			break;
844		default:
845			return errSecUnimplemented;
846	}
847
848	/* make a usage constraints dictionary */
849	CFRef<CFMutableDictionaryRef> usageDict(CFDictionaryCreateMutable(NULL,
850		0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
851	CFDictionaryAddValue(usageDict, kSecTrustSettingsPolicy, policy);
852	if(tsResult != kSecTrustSettingsResultTrustRoot) {
853		/* skip if we're specifying the default */
854		SInt32 result = tsResult;
855		CFNumberRef cfNum = CFNumberCreate(NULL, kCFNumberSInt32Type, &result);
856		CFDictionarySetValue(usageDict, kSecTrustSettingsResult, cfNum);
857		CFRelease(cfNum);
858	}
859	return SecTrustSettingsSetTrustSettings(certificate, kSecTrustSettingsDomainUser,
860		usageDict);
861}
862
863//
864// This one is the now-private version of what SecTrustSetUserTrust() used to
865// be. The public API can no longer manipulate User Trust settings, only
866// view them.
867//
868OSStatus SecTrustSetUserTrustLegacy(SecCertificateRef certificate,
869    SecPolicyRef policy, SecTrustUserSetting trustSetting)
870{
871	BEGIN_SECAPI
872	switch (trustSetting) {
873    case kSecTrustResultProceed:
874    case kSecTrustResultConfirm:
875    case kSecTrustResultDeny:
876    case kSecTrustResultUnspecified:
877		break;
878	default:
879		MacOSError::throwMe(errSecInvalidTrustSetting);
880	}
881	Trust::gStore().assign(
882		Certificate::required(certificate),
883		Policy::required(policy),
884		trustSetting);
885	END_SECAPI
886}
887
888/*   SecGetAppleTPHandle - @@@NOT EXPORTED YET; copied from SecurityInterface,
889                           but could be useful in the future.
890*/
891/*
892CSSM_TP_HANDLE
893SecGetAppleTPHandle()
894{
895	BEGIN_SECAPI
896	return TP(gGuidAppleX509TP)->handle();
897	END_SECAPI1(NULL);
898}
899*/
900
901
902