]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
4d3cab3d | 2 | * Copyright (c) 2002-2010,2012-2013 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
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" | |
427c49bc | 29 | #include "SecInternal.h" |
4d3cab3d | 30 | #include "SecInternalP.h" |
b1ab9ed8 A |
31 | #include "SecTrustSettings.h" |
32 | #include "SecCertificatePriv.h" | |
4d3cab3d A |
33 | #include "SecCertificateP.h" |
34 | #include "SecCertificatePrivP.h" | |
b1ab9ed8 | 35 | #include <security_utilities/cfutilities.h> |
427c49bc | 36 | #include <security_utilities/cfmunge.h> |
b1ab9ed8 A |
37 | #include <CoreFoundation/CoreFoundation.h> |
38 | ||
427c49bc A |
39 | // forward declarations |
40 | CFArrayRef SecTrustCopyDetails(SecTrustRef trust); | |
41 | static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix); | |
42 | static void SecTrustCheckException(const void *key, const void *value, void *context); | |
43 | ||
44 | typedef struct SecTrustCheckExceptionContext { | |
45 | CFDictionaryRef exception; | |
46 | bool exceptionNotFound; | |
47 | } SecTrustCheckExceptionContext; | |
48 | ||
49 | // public trust result constants | |
50 | CFTypeRef kSecTrustEvaluationDate = CFSTR("TrustEvaluationDate"); | |
51 | CFTypeRef kSecTrustExtendedValidation = CFSTR("TrustExtendedValidation"); | |
52 | CFTypeRef kSecTrustOrganizationName = CFSTR("Organization"); | |
53 | CFTypeRef kSecTrustResultValue = CFSTR("TrustResultValue"); | |
54 | CFTypeRef kSecTrustRevocationChecked = CFSTR("TrustRevocationChecked"); | |
55 | CFTypeRef kSecTrustRevocationValidUntilDate = CFSTR("TrustExpirationDate"); | |
56 | CFTypeRef kSecTrustResultDetails = CFSTR("TrustResultDetails"); | |
b1ab9ed8 A |
57 | |
58 | // | |
59 | // CF boilerplate | |
60 | // | |
61 | CFTypeID 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 | // | |
74 | OSStatus SecTrustCreateWithCertificates( | |
427c49bc | 75 | CFTypeRef certificates, |
b1ab9ed8 A |
76 | CFTypeRef policies, |
77 | SecTrustRef *trustRef) | |
78 | { | |
427c49bc | 79 | BEGIN_SECAPI |
b1ab9ed8 | 80 | Required(trustRef); |
427c49bc A |
81 | *trustRef = (new Trust(certificates, policies))->handle(); |
82 | END_SECAPI | |
b1ab9ed8 A |
83 | } |
84 | ||
85 | OSStatus | |
86 | SecTrustSetPolicies(SecTrustRef trustRef, CFTypeRef policies) | |
87 | { | |
88 | BEGIN_SECAPI | |
89 | Trust::required(trustRef)->policies(policies); | |
90 | END_SECAPI | |
91 | } | |
92 | ||
93 | OSStatus | |
94 | SecTrustSetOptions(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 | ||
111 | OSStatus 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 | ||
124 | OSStatus SecTrustSetAnchorCertificates(SecTrustRef trust, CFArrayRef anchorCertificates) | |
125 | { | |
126 | BEGIN_SECAPI | |
127 | Trust::required(trust)->anchors(anchorCertificates); | |
128 | END_SECAPI | |
129 | } | |
130 | ||
131 | OSStatus 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 | ||
139 | OSStatus SecTrustSetKeychains(SecTrustRef trust, CFTypeRef keychainOrArray) | |
140 | { | |
427c49bc A |
141 | BEGIN_SECAPI |
142 | StorageManager::KeychainList keychains; | |
b1ab9ed8 A |
143 | // avoid unnecessary global initializations if an empty array is passed in |
144 | if (!( (keychainOrArray != NULL) && | |
427c49bc A |
145 | (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && |
146 | (CFArrayGetCount((CFArrayRef)keychainOrArray) == 0) )) { | |
b1ab9ed8 A |
147 | globals().storageManager.optionalSearchList(keychainOrArray, keychains); |
148 | } | |
427c49bc A |
149 | Trust::required(trust)->searchLibs(keychains); |
150 | END_SECAPI | |
b1ab9ed8 A |
151 | } |
152 | ||
153 | ||
154 | OSStatus SecTrustSetVerifyDate(SecTrustRef trust, CFDateRef verifyDate) | |
155 | { | |
156 | BEGIN_SECAPI | |
157 | Trust::required(trust)->time(verifyDate); | |
158 | END_SECAPI | |
159 | } | |
160 | ||
161 | ||
162 | CFAbsoluteTime SecTrustGetVerifyTime(SecTrustRef trust) | |
163 | { | |
164 | CFAbsoluteTime verifyTime = 0; | |
427c49bc | 165 | OSStatus __secapiresult = errSecSuccess; |
b1ab9ed8 A |
166 | try { |
167 | CFRef<CFDateRef> verifyDate = Trust::required(trust)->time(); | |
168 | verifyTime = CFDateGetAbsoluteTime(verifyDate); | |
b1ab9ed8 A |
169 | } |
170 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
171 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
427c49bc A |
172 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } |
173 | catch (...) { __secapiresult=errSecInternalComponent; } | |
174 | return verifyTime; | |
b1ab9ed8 A |
175 | } |
176 | ||
427c49bc | 177 | |
427c49bc | 178 | OSStatus SecTrustEvaluate(SecTrustRef trust, SecTrustResultType *resultP) |
b1ab9ed8 | 179 | { |
427c49bc A |
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; | |
b1ab9ed8 A |
232 | } |
233 | ||
234 | OSStatus 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(); | |
427c49bc A |
242 | SecTrustResultType trustResult = trustObj->result(); |
243 | result(trust, trustResult); | |
b1ab9ed8 A |
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 | // | |
255 | OSStatus 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 | // | |
272 | OSStatus 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 | // | |
284 | OSStatus SecTrustCopyExtendedResult(SecTrustRef trust, CFDictionaryRef *result) | |
285 | { | |
286 | BEGIN_SECAPI | |
287 | Trust *trustObj = Trust::required(trust); | |
288 | if (result == nil) | |
427c49bc | 289 | return errSecParam; |
b1ab9ed8 A |
290 | trustObj->extendedResult(*result); |
291 | END_SECAPI | |
292 | } | |
293 | ||
294 | // | |
295 | // Retrieve CSSM-level information for those who want to dig down | |
296 | // | |
297 | OSStatus 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 | // | |
307 | OSStatus SecTrustGetCssmResultCode(SecTrustRef trustRef, OSStatus *result) | |
308 | { | |
427c49bc A |
309 | BEGIN_SECAPI |
310 | Trust *trust = Trust::required(trustRef); | |
b1ab9ed8 | 311 | if (trust->result() == kSecTrustResultInvalid) |
427c49bc | 312 | return errSecParam; |
b1ab9ed8 A |
313 | else |
314 | Required(result) = trust->cssmResultCode(); | |
427c49bc | 315 | END_SECAPI |
b1ab9ed8 A |
316 | } |
317 | ||
318 | OSStatus SecTrustGetTPHandle(SecTrustRef trust, CSSM_TP_HANDLE *handle) | |
319 | { | |
427c49bc A |
320 | BEGIN_SECAPI |
321 | Required(handle) = Trust::required(trust)->getTPHandle(); | |
322 | END_SECAPI | |
b1ab9ed8 A |
323 | } |
324 | ||
325 | OSStatus SecTrustCopyPolicies(SecTrustRef trust, CFArrayRef *policies) | |
326 | { | |
427c49bc A |
327 | BEGIN_SECAPI |
328 | CFArrayRef currentPolicies = Trust::required(trust)->policies(); | |
b1ab9ed8 A |
329 | if (currentPolicies != NULL) |
330 | { | |
331 | CFRetain(currentPolicies); | |
332 | } | |
333 | ||
427c49bc A |
334 | Required(policies) = currentPolicies; |
335 | END_SECAPI | |
336 | } | |
337 | ||
338 | OSStatus 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 | ||
348 | OSStatus 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 | ||
365 | OSStatus SecTrustSetOCSPResponse(SecTrustRef trust, CFTypeRef responseData) | |
366 | { | |
367 | BEGIN_SECAPI | |
368 | Trust::required(trust)->responses(responseData); | |
369 | END_SECAPI | |
b1ab9ed8 A |
370 | } |
371 | ||
372 | OSStatus SecTrustCopyCustomAnchorCertificates(SecTrustRef trust, CFArrayRef *anchorCertificates) | |
373 | { | |
427c49bc A |
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 | |
b1ab9ed8 A |
379 | } |
380 | ||
381 | // | |
382 | // Get the user's default anchor certificate set | |
383 | // | |
384 | OSStatus SecTrustCopyAnchorCertificates(CFArrayRef *anchorCertificates) | |
385 | { | |
427c49bc | 386 | BEGIN_SECAPI |
b1ab9ed8 A |
387 | |
388 | return SecTrustSettingsCopyUnrestrictedRoots( | |
427c49bc A |
389 | true, true, true, /* all domains */ |
390 | anchorCertificates); | |
b1ab9ed8 | 391 | |
427c49bc | 392 | END_SECAPI |
b1ab9ed8 A |
393 | } |
394 | ||
395 | /* new in 10.6 */ | |
396 | SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust) | |
397 | { | |
398 | SecKeyRef pubKey = NULL; | |
399 | CFArrayRef certChain = NULL; | |
400 | CFArrayRef evidenceChain = NULL; | |
401 | CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; | |
427c49bc | 402 | OSStatus __secapiresult = errSecSuccess; |
b1ab9ed8 A |
403 | try { |
404 | Trust *trustObj = Trust::required(trust); | |
405 | if (trustObj->result() == kSecTrustResultInvalid) | |
406 | MacOSError::throwMe(errSecTrustNotAvailable); | |
407 | if (trustObj->evidence() == nil) | |
408 | trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain)); | |
409 | evidenceChain = trustObj->evidence(); | |
b1ab9ed8 A |
410 | } |
411 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
412 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
427c49bc A |
413 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } |
414 | catch (...) { __secapiresult=errSecInternalComponent; } | |
b1ab9ed8 A |
415 | |
416 | if (certChain) | |
417 | CFRelease(certChain); | |
418 | ||
419 | if (evidenceChain) { | |
420 | if (CFArrayGetCount(evidenceChain) > 0) { | |
421 | SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(evidenceChain, 0); | |
422 | __secapiresult = SecCertificateCopyPublicKey(cert, &pubKey); | |
423 | } | |
424 | // do not release evidenceChain, as it is owned by the trust object. | |
425 | } | |
427c49bc | 426 | return pubKey; |
b1ab9ed8 A |
427 | } |
428 | ||
429 | /* new in 10.6 */ | |
430 | CFIndex SecTrustGetCertificateCount(SecTrustRef trust) | |
431 | { | |
432 | CFIndex chainLen = 0; | |
433 | CFArrayRef certChain = NULL; | |
434 | CFArrayRef evidenceChain = NULL; | |
435 | CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; | |
427c49bc | 436 | OSStatus __secapiresult = errSecSuccess; |
b1ab9ed8 A |
437 | try { |
438 | Trust *trustObj = Trust::required(trust); | |
427c49bc A |
439 | if (trustObj->result() == kSecTrustResultInvalid) { |
440 | trustObj->evaluate(); | |
441 | if (trustObj->result() == kSecTrustResultInvalid) | |
442 | MacOSError::throwMe(errSecTrustNotAvailable); | |
443 | } | |
b1ab9ed8 A |
444 | if (trustObj->evidence() == nil) |
445 | trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain)); | |
446 | evidenceChain = trustObj->evidence(); | |
b1ab9ed8 A |
447 | } |
448 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
449 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
427c49bc A |
450 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } |
451 | catch (...) { __secapiresult=errSecInternalComponent; } | |
b1ab9ed8 A |
452 | |
453 | if (certChain) | |
454 | CFRelease(certChain); | |
455 | ||
456 | if (evidenceChain) | |
457 | chainLen = CFArrayGetCount(evidenceChain); // don't release, trust object owns it. | |
458 | ||
459 | return chainLen; | |
460 | } | |
461 | ||
462 | /* new in 10.6 */ | |
463 | SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust, CFIndex ix) | |
464 | { | |
465 | SecCertificateRef certificate = NULL; | |
466 | CFArrayRef certChain = NULL; | |
467 | CFArrayRef evidenceChain = NULL; | |
468 | CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; | |
427c49bc | 469 | OSStatus __secapiresult = errSecSuccess; |
b1ab9ed8 A |
470 | try { |
471 | Trust *trustObj = Trust::required(trust); | |
427c49bc A |
472 | if (trustObj->result() == kSecTrustResultInvalid) { |
473 | trustObj->evaluate(); | |
474 | if (trustObj->result() == kSecTrustResultInvalid) | |
475 | MacOSError::throwMe(errSecTrustNotAvailable); | |
476 | } | |
b1ab9ed8 A |
477 | if (trustObj->evidence() == nil) |
478 | trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain)); | |
479 | evidenceChain = trustObj->evidence(); | |
b1ab9ed8 A |
480 | } |
481 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
482 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
427c49bc A |
483 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } |
484 | catch (...) { __secapiresult=errSecInternalComponent; } | |
b1ab9ed8 A |
485 | |
486 | if (certChain) | |
487 | CFRelease(certChain); | |
488 | ||
489 | if (evidenceChain) { | |
490 | if (ix < CFArrayGetCount(evidenceChain)) { | |
491 | certificate = (SecCertificateRef) CFArrayGetValueAtIndex(evidenceChain, ix); | |
492 | // note: we do not retain this certificate. The assumption here is | |
493 | // that the certificate is retained by the trust object, so it is | |
494 | // valid unil the trust is released (or until re-evaluated.) | |
495 | // also note: we do not release the evidenceChain, as it is owned | |
496 | // by the trust object. | |
497 | } | |
498 | } | |
499 | return certificate; | |
500 | } | |
501 | ||
427c49bc A |
502 | |
503 | static CFStringRef kSecCertificateDetailSHA1Digest = CFSTR("SHA1Digest"); | |
504 | static CFStringRef kSecCertificateDetailStatusCodes = CFSTR("StatusCodes"); | |
505 | ||
506 | static void | |
507 | _AppendStatusCode(CFMutableArrayRef array, OSStatus statusCode) | |
508 | { | |
509 | if (!array) | |
510 | return; | |
511 | SInt32 num = statusCode; | |
512 | CFNumberRef numRef = CFNumberCreate(NULL, kCFNumberSInt32Type, &num); | |
513 | if (!numRef) | |
514 | return; | |
515 | CFArrayAppendValue(array, numRef); | |
516 | CFRelease(numRef); | |
517 | } | |
518 | ||
519 | CFArrayRef SecTrustCopyDetails(SecTrustRef trust) | |
520 | { | |
521 | // This function returns an array of dictionaries, one per certificate, | |
522 | // holding status info for each certificate in the evaluated chain. | |
523 | // | |
524 | CFIndex count, chainLen = 0; | |
525 | CFArrayRef certChain = NULL; | |
526 | CFMutableArrayRef details = NULL; | |
527 | CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; | |
528 | OSStatus __secapiresult = errSecSuccess; | |
529 | try { | |
530 | Trust *trustObj = Trust::required(trust); | |
531 | if (trustObj->result() == kSecTrustResultInvalid) { | |
532 | trustObj->evaluate(); | |
533 | if (trustObj->result() == kSecTrustResultInvalid) | |
534 | MacOSError::throwMe(errSecTrustNotAvailable); | |
535 | } | |
536 | trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain)); | |
537 | } | |
538 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
539 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
540 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } | |
541 | catch (...) { __secapiresult=errSecInternalComponent; } | |
542 | ||
543 | if (certChain) { | |
544 | chainLen = CFArrayGetCount(certChain); | |
545 | CFRelease(certChain); | |
546 | } | |
547 | if (statusChain) { | |
548 | details = CFArrayCreateMutable(NULL, chainLen, &kCFTypeArrayCallBacks); | |
549 | for (count = 0; count < chainLen; count++) { | |
550 | CFMutableDictionaryRef certDict = CFDictionaryCreateMutable(kCFAllocatorDefault, | |
551 | 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
552 | CFMutableArrayRef statusCodes = CFArrayCreateMutable(kCFAllocatorDefault, | |
553 | 0, &kCFTypeArrayCallBacks); | |
554 | CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &statusChain[count]; | |
555 | CSSM_TP_APPLE_CERT_STATUS statBits = evInfo->StatusBits; | |
556 | ||
557 | // translate status bits | |
558 | if (statBits & CSSM_CERT_STATUS_EXPIRED) | |
559 | _AppendStatusCode(statusCodes, errSecCertificateExpired); | |
560 | if (statBits & CSSM_CERT_STATUS_NOT_VALID_YET) | |
561 | _AppendStatusCode(statusCodes, errSecCertificateNotValidYet); | |
562 | if (statBits & CSSM_CERT_STATUS_TRUST_SETTINGS_DENY) | |
563 | _AppendStatusCode(statusCodes, errSecTrustSettingDeny); | |
564 | ||
565 | // translate status codes | |
566 | unsigned int i; | |
567 | for (i = 0; i < evInfo->NumStatusCodes; i++) { | |
568 | CSSM_RETURN scode = evInfo->StatusCodes[i]; | |
569 | _AppendStatusCode(statusCodes, (OSStatus)scode); | |
570 | } | |
571 | ||
572 | CFDictionarySetValue(certDict, kSecCertificateDetailStatusCodes, statusCodes); | |
573 | CFRelease(statusCodes); | |
574 | CFArrayAppendValue(details, certDict); | |
575 | CFRelease(certDict); | |
576 | } | |
577 | } | |
578 | return details; | |
579 | } | |
580 | ||
581 | static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix) | |
582 | { | |
583 | CFArrayRef exceptions = NULL; | |
584 | OSStatus __secapiresult = errSecSuccess; | |
585 | try { | |
586 | exceptions = Trust::required(trust)->exceptions(); | |
587 | } | |
588 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
589 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
590 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } | |
591 | catch (...) { __secapiresult=errSecInternalComponent; } | |
592 | ||
593 | if (!exceptions || ix >= CFArrayGetCount(exceptions)) | |
594 | return NULL; | |
595 | CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix); | |
596 | if (CFGetTypeID(exception) != CFDictionaryGetTypeID()) | |
597 | return NULL; | |
598 | ||
599 | SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix); | |
600 | if (!certificate) | |
601 | return NULL; | |
602 | ||
603 | /* If the exception contains the current certificate's sha1Digest in the | |
604 | kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */ | |
605 | CFDataRef sha1Digest = SecCertificateGetSHA1Digest(certificate); | |
606 | CFTypeRef digestValue = CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest); | |
607 | if (!digestValue || !CFEqual(sha1Digest, digestValue)) | |
608 | exception = NULL; | |
609 | ||
610 | return exception; | |
611 | } | |
612 | ||
613 | static void SecTrustCheckException(const void *key, const void *value, void *context) | |
614 | { | |
615 | struct SecTrustCheckExceptionContext *cec = (struct SecTrustCheckExceptionContext *)context; | |
616 | if (cec->exception) { | |
617 | CFTypeRef exceptionValue = CFDictionaryGetValue(cec->exception, key); | |
618 | if (!exceptionValue || !CFEqual(value, exceptionValue)) { | |
619 | cec->exceptionNotFound = true; | |
620 | } | |
621 | } else { | |
622 | cec->exceptionNotFound = true; | |
623 | } | |
624 | } | |
625 | ||
626 | /* new in 10.9 */ | |
627 | CFDataRef SecTrustCopyExceptions(SecTrustRef trust) | |
628 | { | |
629 | CFArrayRef details = SecTrustCopyDetails(trust); | |
630 | CFIndex pathLength = details ? CFArrayGetCount(details) : 0; | |
631 | CFMutableArrayRef exceptions = CFArrayCreateMutable(kCFAllocatorDefault, | |
632 | pathLength, &kCFTypeArrayCallBacks); | |
633 | CFIndex ix; | |
634 | for (ix = 0; ix < pathLength; ++ix) { | |
635 | CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix); | |
636 | CFIndex detailCount = CFDictionaryGetCount(detail); | |
637 | CFMutableDictionaryRef exception; | |
638 | if (ix == 0 || detailCount > 0) { | |
639 | exception = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, | |
640 | detailCount + 1, detail); | |
641 | SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix); | |
642 | CFDataRef digest = SecCertificateGetSHA1Digest(certificate); | |
643 | if (digest) { | |
644 | CFDictionaryAddValue(exception, kSecCertificateDetailSHA1Digest, digest); | |
645 | } | |
646 | } else { | |
647 | /* Add empty exception dictionaries for non leaf certs which have no exceptions | |
648 | * to save space. | |
649 | */ | |
650 | exception = (CFMutableDictionaryRef)CFDictionaryCreate(kCFAllocatorDefault, | |
651 | NULL, NULL, 0, | |
652 | &kCFTypeDictionaryKeyCallBacks, | |
653 | &kCFTypeDictionaryValueCallBacks); | |
654 | } | |
655 | CFArrayAppendValue(exceptions, exception); | |
656 | CFReleaseNull(exception); | |
657 | } | |
658 | CFReleaseSafe(details); | |
659 | ||
660 | /* Remove any trailing empty dictionaries to save even more space (we skip the leaf | |
661 | since it will never be empty). */ | |
662 | for (ix = pathLength; ix-- > 1;) { | |
663 | CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix); | |
664 | if (CFDictionaryGetCount(exception) == 0) { | |
665 | CFArrayRemoveValueAtIndex(exceptions, ix); | |
666 | } else { | |
667 | break; | |
668 | } | |
669 | } | |
670 | ||
671 | CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault, | |
672 | exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL); | |
673 | CFRelease(exceptions); | |
674 | ||
675 | return encodedExceptions; | |
676 | } | |
677 | ||
678 | /* new in 10.9 */ | |
679 | bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions) | |
680 | { | |
681 | CFArrayRef exceptions; | |
682 | exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault, | |
683 | encodedExceptions, kCFPropertyListImmutable, NULL, NULL); | |
684 | if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) { | |
685 | CFRelease(exceptions); | |
686 | exceptions = NULL; | |
687 | } | |
688 | ||
689 | OSStatus __secapiresult = errSecSuccess; | |
690 | try { | |
691 | Trust::required(trust)->exceptions(exceptions); | |
692 | } | |
693 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
694 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
695 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } | |
696 | catch (...) { __secapiresult=errSecInternalComponent; } | |
697 | ||
698 | /* If there is a valid exception entry for our current leaf we're golden. */ | |
699 | if (SecTrustGetExceptionForCertificateAtIndex(trust, 0)) | |
700 | return true; | |
701 | ||
702 | /* The passed in exceptions didn't match our current leaf, so we discard it. */ | |
703 | try { | |
704 | Trust::required(trust)->exceptions(NULL); | |
705 | __secapiresult = errSecSuccess; | |
706 | } | |
707 | catch (const MacOSError &err) { __secapiresult=err.osStatus(); } | |
708 | catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } | |
709 | catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } | |
710 | catch (...) { __secapiresult=errSecInternalComponent; } | |
711 | ||
712 | return false; | |
713 | } | |
714 | ||
715 | /* new in 10.9 */ | |
716 | CFDictionaryRef | |
717 | SecTrustCopyResult(SecTrustRef trust) | |
718 | { | |
719 | CFDictionaryRef result = NULL; | |
720 | try { | |
721 | result = Trust::required(trust)->results(); | |
722 | // merge details into result | |
723 | CFArrayRef details = SecTrustCopyDetails(trust); | |
724 | if (details) { | |
725 | CFDictionarySetValue((CFMutableDictionaryRef)result, | |
726 | kSecTrustResultDetails, details); | |
727 | CFRelease(details); | |
728 | } | |
729 | } | |
730 | catch (...) { | |
731 | if (result) { | |
732 | CFRelease(result); | |
733 | result = NULL; | |
734 | } | |
735 | } | |
736 | return result; | |
737 | } | |
738 | ||
b1ab9ed8 A |
739 | /* new in 10.7 */ |
740 | CFArrayRef | |
741 | SecTrustCopyProperties(SecTrustRef trust) | |
742 | { | |
743 | /* can't use SECAPI macros, since this function does not return OSStatus */ | |
744 | CFArrayRef result = NULL; | |
745 | try { | |
746 | result = Trust::required(trust)->properties(); | |
747 | } | |
748 | catch (...) { | |
749 | if (result) { | |
750 | CFRelease(result); | |
751 | result = NULL; | |
752 | } | |
427c49bc | 753 | } |
b1ab9ed8 A |
754 | return result; |
755 | } | |
756 | ||
757 | ||
758 | /* deprecated in 10.5 */ | |
759 | OSStatus SecTrustGetCSSMAnchorCertificates(const CSSM_DATA **cssmAnchors, | |
760 | uint32 *cssmAnchorCount) | |
761 | { | |
762 | BEGIN_SECAPI | |
763 | CertGroup certs; | |
764 | Trust::gStore().getCssmRootCertificates(certs); | |
765 | Required(cssmAnchors) = certs.blobCerts(); | |
766 | Required(cssmAnchorCount) = certs.count(); | |
767 | END_SECAPI | |
768 | } | |
769 | ||
770 | ||
771 | // | |
772 | // Get and set user trust settings. Deprecated in 10.5. | |
773 | // User Trust getter, deprecated, works as it always has. | |
774 | // | |
775 | OSStatus SecTrustGetUserTrust(SecCertificateRef certificate, | |
776 | SecPolicyRef policy, SecTrustUserSetting *trustSetting) | |
777 | { | |
778 | BEGIN_SECAPI | |
779 | StorageManager::KeychainList searchList; | |
780 | globals().storageManager.getSearchList(searchList); | |
781 | Required(trustSetting) = Trust::gStore().find( | |
782 | Certificate::required(certificate), | |
783 | Policy::required(policy), | |
784 | searchList); | |
785 | END_SECAPI | |
786 | } | |
787 | ||
788 | // | |
789 | // The public setter, also deprecated; it maps to the appropriate | |
427c49bc | 790 | // Trust Settings call if possible, else throws errSecUnimplemented. |
b1ab9ed8 A |
791 | // |
792 | OSStatus SecTrustSetUserTrust(SecCertificateRef certificate, | |
793 | SecPolicyRef policy, SecTrustUserSetting trustSetting) | |
794 | { | |
795 | SecTrustSettingsResult tsResult = kSecTrustSettingsResultInvalid; | |
796 | OSStatus ortn; | |
797 | Boolean isRoot; | |
798 | ||
799 | Policy::required(policy); | |
800 | switch(trustSetting) { | |
801 | case kSecTrustResultProceed: | |
802 | /* different SecTrustSettingsResult depending in root-ness */ | |
803 | ortn = SecCertificateIsSelfSigned(certificate, &isRoot); | |
804 | if(ortn) { | |
805 | return ortn; | |
806 | } | |
807 | if(isRoot) { | |
808 | tsResult = kSecTrustSettingsResultTrustRoot; | |
809 | } | |
810 | else { | |
811 | tsResult = kSecTrustSettingsResultTrustAsRoot; | |
812 | } | |
813 | break; | |
814 | case kSecTrustResultDeny: | |
815 | tsResult = kSecTrustSettingsResultDeny; | |
816 | break; | |
817 | default: | |
427c49bc | 818 | return errSecUnimplemented; |
b1ab9ed8 A |
819 | } |
820 | ||
821 | /* make a usage constraints dictionary */ | |
822 | CFRef<CFMutableDictionaryRef> usageDict(CFDictionaryCreateMutable(NULL, | |
823 | 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); | |
824 | CFDictionaryAddValue(usageDict, kSecTrustSettingsPolicy, policy); | |
825 | if(tsResult != kSecTrustSettingsResultTrustRoot) { | |
826 | /* skip if we're specifying the default */ | |
827 | SInt32 result = tsResult; | |
828 | CFNumberRef cfNum = CFNumberCreate(NULL, kCFNumberSInt32Type, &result); | |
829 | CFDictionarySetValue(usageDict, kSecTrustSettingsResult, cfNum); | |
830 | CFRelease(cfNum); | |
831 | } | |
832 | return SecTrustSettingsSetTrustSettings(certificate, kSecTrustSettingsDomainUser, | |
833 | usageDict); | |
834 | } | |
835 | ||
836 | // | |
837 | // This one is the now-private version of what SecTrustSetUserTrust() used to | |
838 | // be. The public API can no longer manipulate User Trust settings, only | |
839 | // view them. | |
840 | // | |
841 | OSStatus SecTrustSetUserTrustLegacy(SecCertificateRef certificate, | |
842 | SecPolicyRef policy, SecTrustUserSetting trustSetting) | |
843 | { | |
844 | BEGIN_SECAPI | |
845 | switch (trustSetting) { | |
846 | case kSecTrustResultProceed: | |
847 | case kSecTrustResultConfirm: | |
848 | case kSecTrustResultDeny: | |
849 | case kSecTrustResultUnspecified: | |
850 | break; | |
851 | default: | |
852 | MacOSError::throwMe(errSecInvalidTrustSetting); | |
853 | } | |
854 | Trust::gStore().assign( | |
855 | Certificate::required(certificate), | |
856 | Policy::required(policy), | |
857 | trustSetting); | |
858 | END_SECAPI | |
859 | } | |
860 | ||
861 | /* SecGetAppleTPHandle - @@@NOT EXPORTED YET; copied from SecurityInterface, | |
862 | but could be useful in the future. | |
863 | */ | |
864 | /* | |
865 | CSSM_TP_HANDLE | |
866 | SecGetAppleTPHandle() | |
867 | { | |
868 | BEGIN_SECAPI | |
869 | return TP(gGuidAppleX509TP)->handle(); | |
870 | END_SECAPI1(NULL); | |
871 | } | |
872 | */ | |
873 | ||
874 |