]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/SecTrust.cpp
Security-57740.60.18.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecTrust.cpp
1 /*
2 * Copyright (c) 2002-2016 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 "SecBase.h"
28 #include "SecBridge.h"
29 #include "SecInternal.h"
30 #include "SecTrustSettings.h"
31 #include "SecTrustSettingsPriv.h"
32 #include "SecCertificatePriv.h"
33 #include "SecCertificateP.h"
34 #include "SecCertificatePrivP.h"
35 #include "SecPolicyPriv.h"
36 #include <security_utilities/cfutilities.h>
37 #include <security_utilities/cfmunge.h>
38 #include <CoreFoundation/CoreFoundation.h>
39 #include <syslog.h>
40
41 // forward declarations
42 CFArrayRef SecTrustCopyInputCertificates(SecTrustRef trust);
43 CFArrayRef SecTrustCopyInputAnchors(SecTrustRef trust);
44 CFArrayRef SecTrustCopyConstructedChain(SecTrustRef trust);
45 static CSSM_TP_APPLE_EVIDENCE_INFO * SecTrustGetEvidenceInfo(SecTrustRef trust);
46
47 typedef struct SecTrustCheckExceptionContext {
48 CFDictionaryRef exception;
49 bool exceptionNotFound;
50 } SecTrustCheckExceptionContext;
51
52 // public trust result constants
53 const CFStringRef kSecTrustEvaluationDate = CFSTR("TrustEvaluationDate");
54 const CFStringRef kSecTrustExtendedValidation = CFSTR("TrustExtendedValidation");
55 const CFStringRef kSecTrustOrganizationName = CFSTR("Organization");
56 const CFStringRef kSecTrustResultValue = CFSTR("TrustResultValue");
57 const CFStringRef kSecTrustRevocationChecked = CFSTR("TrustRevocationChecked");
58 const CFStringRef kSecTrustRevocationReason = CFSTR("TrustRevocationReason");
59 const CFStringRef kSecTrustRevocationValidUntilDate = CFSTR("TrustExpirationDate");
60 const CFStringRef kSecTrustResultDetails = CFSTR("TrustResultDetails");
61
62 // Policy check string to CSSM_RETURN mapping
63
64 struct resultmap_entry_s {
65 const CFStringRef checkstr;
66 const CSSM_RETURN resultcode;
67 };
68 typedef struct resultmap_entry_s resultmap_entry_t;
69
70 const resultmap_entry_t cssmresultmap[] = {
71 { CFSTR("SSLHostname"), CSSMERR_APPLETP_HOSTNAME_MISMATCH },
72 { CFSTR("email"), CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND },
73 { CFSTR("IssuerCommonName"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
74 { CFSTR("SubjectCommonName"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
75 { CFSTR("SubjectCommonNamePrefix"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
76 { CFSTR("SubjectCommonNameTEST"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
77 { CFSTR("SubjectOrganization"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
78 { CFSTR("SubjectOrganizationalUnit"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
79 { CFSTR("EAPTrustedServerNames"), CSSMERR_APPLETP_HOSTNAME_MISMATCH },
80 { CFSTR("CertificatePolicy"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION },
81 { CFSTR("KeyUsage"), CSSMERR_APPLETP_INVALID_KEY_USAGE },
82 { CFSTR("ExtendedKeyUsage"), CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE },
83 { CFSTR("BasicConstraints"), CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS },
84 { CFSTR("QualifiedCertStatements"), CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT },
85 { CFSTR("IntermediateSPKISHA256"), CSSMERR_APPLETP_IDENTIFIER_MISSING },
86 { CFSTR("IntermediateEKU"), CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE },
87 { CFSTR("AnchorSHA1"), CSSMERR_TP_NOT_TRUSTED },
88 { CFSTR("AnchorSHA256"), CSSMERR_TP_NOT_TRUSTED },
89 { CFSTR("AnchorTrusted"), CSSMERR_TP_NOT_TRUSTED },
90 { CFSTR("AnchorApple"), CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH },
91 { CFSTR("NonEmptySubject"), CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT },
92 { CFSTR("IdLinkage"), CSSMERR_APPLETP_INVALID_AUTHORITY_ID },
93 { CFSTR("WeakIntermediates"), CSSMERR_TP_INVALID_CERTIFICATE },
94 { CFSTR("WeakLeaf"), CSSMERR_TP_INVALID_CERTIFICATE },
95 { CFSTR("WeakRoot"), CSSMERR_TP_INVALID_CERTIFICATE },
96 { CFSTR("KeySize"), CSSMERR_CSP_UNSUPPORTED_KEY_SIZE },
97 { CFSTR("SignatureHashAlgorithms"), CSSMERR_CSP_ALGID_MISMATCH },
98 { CFSTR("SystemTrustedWeakHash"), CSSMERR_CSP_INVALID_DIGEST_ALGORITHM },
99 { CFSTR("CriticalExtensions"), CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN },
100 { CFSTR("ChainLength"), CSSMERR_APPLETP_PATH_LEN_CONSTRAINT },
101 { CFSTR("BasicCertificateProcessing"), CSSMERR_TP_INVALID_CERTIFICATE },
102 { CFSTR("ExtendedValidation"), CSSMERR_TP_NOT_TRUSTED },
103 { CFSTR("Revocation"), CSSMERR_TP_CERT_REVOKED },
104 { CFSTR("RevocationResponseRequired"), CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK },
105 { CFSTR("CertificateTransparency"), CSSMERR_TP_NOT_TRUSTED },
106 { CFSTR("BlackListedLeaf"), CSSMERR_TP_CERT_REVOKED },
107 { CFSTR("GrayListedLeaf"), CSSMERR_TP_NOT_TRUSTED },
108 { CFSTR("GrayListedKey"), CSSMERR_TP_NOT_TRUSTED },
109 { CFSTR("BlackListedKey"), CSSMERR_TP_CERT_REVOKED },
110 { CFSTR("CheckLeafMarkerOid"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION },
111 { CFSTR("CheckLeafMarkerOidNoValueCheck"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION },
112 { CFSTR("CheckIntermediateMarkerOid"), CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION },
113 { CFSTR("UsageConstraints"), CSSMERR_APPLETP_TRUST_SETTING_DENY },
114 { CFSTR("NotValidBefore"), CSSMERR_TP_CERT_NOT_VALID_YET },
115 { CFSTR("ValidIntermediates"), CSSMERR_TP_CERT_EXPIRED },
116 { CFSTR("ValidLeaf"), CSSMERR_TP_CERT_EXPIRED },
117 { CFSTR("ValidRoot"), CSSMERR_TP_CERT_EXPIRED },
118 // { CFSTR("AnchorAppleTestRoots"), },
119 // { CFSTR("AnchorAppleTestRootsOnProduction"), },
120 // { CFSTR("NoNetworkAccess"), },
121 };
122
123
124 //
125 // Sec* API bridge functions
126 //
127 typedef struct {
128 SecTrustOptionFlags flags;
129 CFIndex certIX;
130 SecTrustRef trustRef;
131 CFMutableDictionaryRef filteredException;
132 CFDictionaryRef oldException;
133 } SecExceptionFilterContext;
134
135 // inline function from SecCFWrappers.h
136 static inline char *CFStringToCString(CFStringRef inStr)
137 {
138 if (!inStr)
139 return (char *)strdup("");
140 CFRetain(inStr); // compensate for release on exit
141
142 // need to extract into buffer
143 CFIndex length = CFStringGetLength(inStr); // in 16-bit character units
144 size_t len = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
145 char *buffer = (char *)malloc(len); // pessimistic
146 if (!CFStringGetCString(inStr, buffer, len, kCFStringEncodingUTF8))
147 buffer[0] = 0;
148
149 CFRelease(inStr);
150 return buffer;
151 }
152
153 static void
154 filter_exception(const void *key, const void *value, void *context)
155 {
156 SecExceptionFilterContext *ctx = (SecExceptionFilterContext *)context;
157 if (!ctx) { return; }
158
159 SecTrustOptionFlags options = ctx->flags;
160 CFMutableDictionaryRef filteredException = ctx->filteredException;
161 CFStringRef keystr = (CFStringRef)key;
162
163 if (ctx->oldException && CFDictionaryContainsKey(ctx->oldException, key)) {
164 // Keep existing exception in filtered dictionary, regardless of options
165 CFDictionaryAddValue(filteredException, key, CFDictionaryGetValue(ctx->oldException, key));
166 return;
167 }
168
169 bool allowed = false;
170
171 if (CFEqual(keystr, CFSTR("SHA1Digest"))) {
172 allowed = true; // this key is informational and always permitted
173 }
174 else if (CFEqual(keystr, CFSTR("NotValidBefore"))) {
175 allowed = ((options & kSecTrustOptionAllowExpired) != 0);
176 }
177 else if (CFEqual(keystr, CFSTR("ValidLeaf"))) {
178 allowed = ((options & kSecTrustOptionAllowExpired) != 0);
179 }
180 else if (CFEqual(keystr, CFSTR("ValidIntermediates"))) {
181 allowed = ((options & kSecTrustOptionAllowExpired) != 0);
182 }
183 else if (CFEqual(keystr, CFSTR("ValidRoot"))) {
184 if (((options & kSecTrustOptionAllowExpired) != 0) ||
185 ((options & kSecTrustOptionAllowExpiredRoot) != 0)) {
186 allowed = true;
187 }
188 }
189 else if (CFEqual(keystr, CFSTR("AnchorTrusted"))) {
190 bool implicitAnchors = ((options & kSecTrustOptionImplicitAnchors) != 0);
191 // Implicit anchors option only filters exceptions for self-signed certs
192 if (implicitAnchors && ctx->trustRef &&
193 (ctx->certIX < SecTrustGetCertificateCount(ctx->trustRef))) {
194 Boolean isSelfSigned = false;
195 SecCertificateRef cert = SecTrustGetCertificateAtIndex(ctx->trustRef, ctx->certIX);
196 if (cert && (errSecSuccess == SecCertificateIsSelfSigned(cert, &isSelfSigned)) &&
197 isSelfSigned) {
198 allowed = true;
199 }
200 }
201 }
202 else if (CFEqual(keystr, CFSTR("KeyUsage")) ||
203 CFEqual(keystr, CFSTR("ExtendedKeyUsage")) ||
204 CFEqual(keystr, CFSTR("BasicConstraints")) ||
205 CFEqual(keystr, CFSTR("NonEmptySubject")) ||
206 CFEqual(keystr, CFSTR("IdLinkage"))) {
207 // Cannot override these exceptions
208 allowed = false;
209 }
210 else {
211 // Unhandled exceptions should not be overridden,
212 // but we want to know which ones we're missing
213 char *cstr = CFStringToCString(keystr);
214 syslog(LOG_ERR, "Unfiltered exception: %s", (cstr) ? cstr : "<NULL>");
215 if (cstr) { free(cstr); }
216 allowed = false;
217 }
218
219 if (allowed) {
220 CFDictionaryAddValue(filteredException, key, value);
221 }
222 }
223
224 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */
225 OSStatus
226 SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options)
227 {
228 /* bridge to support API functionality for legacy callers */
229 OSStatus status = errSecSuccess;
230 CFDataRef encodedExceptions = SecTrustCopyExceptions(trustRef);
231 CFArrayRef exceptions = NULL,
232 oldExceptions = SecTrustGetTrustExceptionsArray(trustRef);
233
234 if (encodedExceptions) {
235 exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault,
236 encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
237 CFRelease(encodedExceptions);
238 encodedExceptions = NULL;
239 }
240
241 if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
242 CFRelease(exceptions);
243 exceptions = NULL;
244 }
245
246 if (oldExceptions && exceptions &&
247 CFArrayGetCount(oldExceptions) > CFArrayGetCount(exceptions)) {
248 oldExceptions = NULL;
249 }
250
251 /* verify both exceptions are for the same leaf */
252 if (oldExceptions && exceptions && CFArrayGetCount(oldExceptions) > 0) {
253 CFDictionaryRef oldLeafExceptions = (CFDictionaryRef)CFArrayGetValueAtIndex(oldExceptions, 0);
254 CFDictionaryRef leafExceptions = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, 0);
255 CFDataRef oldDigest = (CFDataRef)CFDictionaryGetValue(oldLeafExceptions, CFSTR("SHA1Digest"));
256 CFDataRef digest = (CFDataRef)CFDictionaryGetValue(leafExceptions, CFSTR("SHA1Digest"));
257 if (!oldDigest || !digest || !CFEqual(oldDigest, digest)) {
258 oldExceptions = NULL;
259 }
260 }
261
262 /* add only those exceptions which are allowed by the supplied options */
263 if (exceptions) {
264 CFMutableArrayRef filteredExceptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
265 CFIndex i, exceptionCount = (filteredExceptions) ? CFArrayGetCount(exceptions) : 0;
266
267 for (i = 0; i < exceptionCount; ++i) {
268 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, i);
269 CFDictionaryRef oldException = NULL;
270 if (oldExceptions && i < CFArrayGetCount(oldExceptions)) {
271 oldException = (CFDictionaryRef)CFArrayGetValueAtIndex(oldExceptions, i);
272 }
273 CFMutableDictionaryRef filteredException = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
274 &kCFTypeDictionaryValueCallBacks);
275 if (exception && filteredException) {
276 SecExceptionFilterContext filterContext = { options, i, trustRef, filteredException, oldException };
277 CFDictionaryApplyFunction(exception, filter_exception, &filterContext);
278 CFArrayAppendValue(filteredExceptions, filteredException);
279 CFRelease(filteredException);
280 }
281 }
282
283 if (filteredExceptions) {
284 CFIndex filteredCount = CFArrayGetCount(filteredExceptions);
285 /* remove empty trailing entries to match iOS behavior */
286 for (i = filteredCount; i-- > 1;) {
287 CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(filteredExceptions, i);
288 if (CFDictionaryGetCount(exception) == 0) {
289 CFArrayRemoveValueAtIndex(filteredExceptions, i);
290 } else {
291 break;
292 }
293 }
294 encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
295 filteredExceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
296 CFRelease(filteredExceptions);
297
298 SecTrustSetExceptions(trustRef, encodedExceptions);
299 CFRelease(encodedExceptions);
300 }
301 CFRelease(exceptions);
302 }
303
304 #if SECTRUST_DEPRECATION_WARNINGS
305 bool displayModifyMsg = false;
306 bool displayNetworkMsg = false;
307 bool displayPolicyMsg = false;
308 const char *baseMsg = "WARNING: SecTrustSetOptions called with";
309 const char *modifyMsg = "Use SecTrustSetExceptions and SecTrustCopyExceptions to modify default trust results.";
310 const char *networkMsg = "Use SecTrustSetNetworkFetchAllowed to specify whether missing certificates can be fetched from the network.";
311 const char *policyMsg = "Use SecPolicyCreateRevocation to specify revocation policy requirements.";
312
313 if (options & kSecTrustOptionAllowExpired) {
314 syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionAllowExpired");
315 displayModifyMsg = true;
316 }
317 if (options & kSecTrustOptionAllowExpiredRoot) {
318 syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionAllowExpiredRoot");
319 displayModifyMsg = true;
320 }
321 if (options & kSecTrustOptionFetchIssuerFromNet) {
322 syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionFetchIssuerFromNet");
323 displayNetworkMsg = true;
324 }
325 if (options & kSecTrustOptionRequireRevPerCert) {
326 syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionRequireRevPerCert");
327 displayPolicyMsg = true;
328 }
329 if (displayModifyMsg || displayNetworkMsg || displayPolicyMsg) {
330 syslog(LOG_ERR, "%s %s %s",
331 (displayModifyMsg) ? modifyMsg : "",
332 (displayNetworkMsg) ? networkMsg : "",
333 (displayPolicyMsg) ? policyMsg : "");
334 }
335 #endif
336
337 return status;
338 }
339
340 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
341 OSStatus SecTrustSetParameters(
342 SecTrustRef trustRef,
343 CSSM_TP_ACTION action,
344 CFDataRef actionData)
345 {
346 /* bridge to support API functionality for legacy callers */
347 OSStatus status;
348 CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0;
349 if (actionData) {
350 CSSM_APPLE_TP_ACTION_DATA *actionDataPtr = (CSSM_APPLE_TP_ACTION_DATA *) CFDataGetBytePtr(actionData);
351 if (actionDataPtr) {
352 actionFlags = actionDataPtr->ActionFlags;
353 }
354 }
355 // note that SecTrustOptionFlags == CSSM_APPLE_TP_ACTION_FLAGS;
356 // both are sizeof(uint32) and the flag values have identical meanings
357 status = SecTrustSetOptions(trustRef, (SecTrustOptionFlags)actionFlags);
358
359 #if SECTRUST_DEPRECATION_WARNINGS
360 syslog(LOG_ERR, "WARNING: SecTrustSetParameters was deprecated in 10.7. Use SecTrustSetOptions instead.");
361 #endif
362
363 return status;
364 }
365
366 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */
367 OSStatus SecTrustSetKeychains(SecTrustRef trust, CFTypeRef keychainOrArray)
368 {
369 /* this function is currently unsupported in unified SecTrust */
370 // TODO: pull all certs out of the specified keychains for the evaluation?
371 #if SECTRUST_DEPRECATION_WARNINGS
372 syslog(LOG_ERR, "WARNING: SecTrustSetKeychains does nothing in 10.11. Use SecTrustSetAnchorCertificates{Only} to provide anchors.");
373 #endif
374 return errSecSuccess;
375 }
376
377 //
378 // Construct the "official" result evidence and return it
379 //
380 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
381 OSStatus SecTrustGetResult(
382 SecTrustRef trustRef,
383 SecTrustResultType *result,
384 CFArrayRef *certChain, CSSM_TP_APPLE_EVIDENCE_INFO **statusChain)
385 {
386 /* bridge to support old functionality */
387 #if SECTRUST_DEPRECATION_WARNINGS
388 syslog(LOG_ERR, "WARNING: SecTrustGetResult has been deprecated since 10.7. Please use SecTrustGetTrustResult instead.");
389 #endif
390 SecTrustResultType trustResult;
391 OSStatus status = SecTrustGetTrustResult(trustRef, &trustResult);
392 if (status != errSecSuccess) {
393 return status;
394 }
395 if (result) {
396 *result = trustResult;
397 }
398 if (certChain) {
399 *certChain = SecTrustCopyConstructedChain(trustRef);
400 }
401 if (statusChain) {
402 *statusChain = SecTrustGetEvidenceInfo(trustRef);
403 }
404 return status;
405 }
406
407 //
408 // Retrieve extended validation trust results
409 //
410 /* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */
411 OSStatus SecTrustCopyExtendedResult(SecTrustRef trust, CFDictionaryRef *result)
412 {
413 /* bridge to support old functionality */
414 #if SECTRUST_DEPRECATION_WARNINGS
415 syslog(LOG_ERR, "WARNING: SecTrustCopyExtendedResult will be deprecated in an upcoming release. Please use SecTrustCopyResult instead.");
416 #endif
417 CFDictionaryRef resultDict = SecTrustCopyResult(trust);
418 if (result == nil) {
419 CFReleaseNull(resultDict);
420 return errSecParam;
421 }
422 *result = resultDict;
423 return errSecSuccess;
424 }
425
426 //
427 // Retrieve CSSM-level information for those who want to dig down
428 //
429 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
430 OSStatus SecTrustGetCssmResult(SecTrustRef trust, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR *result)
431 {
432 /* this function is unsupported in unified SecTrust */
433 #if SECTRUST_DEPRECATION_WARNINGS
434 syslog(LOG_ERR, "WARNING: SecTrustGetCssmResult has been deprecated since 10.7, and has no functional equivalent in 10.11. Please use SecTrustCopyResult instead.");
435 #endif
436 if (result) {
437 *result = NULL;
438 }
439 return errSecServiceNotAvailable;
440 }
441
442 //
443 // Returns a malloced array of CSSM_RETURN values, with the length in numStatusCodes,
444 // for the certificate specified by chain index in the given SecTrustRef.
445 //
446 // To match legacy behavior, the array actually allocates one element more than the
447 // value of numStatusCodes; if the certificate is revoked, the additional element
448 // at the end contains the CrlReason value.
449 //
450 // Caller must free the returned pointer.
451 //
452 static CSSM_RETURN *copyCssmStatusCodes(SecTrustRef trust,
453 unsigned int index, unsigned int *numStatusCodes)
454 {
455 if (!trust || !numStatusCodes) {
456 return NULL;
457 }
458 *numStatusCodes = 0;
459 CFArrayRef details = SecTrustCopyFilteredDetails(trust);
460 CFIndex chainLength = (details) ? CFArrayGetCount(details) : 0;
461 if (!(index < chainLength)) {
462 CFReleaseSafe(details);
463 return NULL;
464 }
465 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, index);
466 CFIndex ix, detailCount = CFDictionaryGetCount(detail);
467 *numStatusCodes = (unsigned int)detailCount;
468
469 // Allocate one more entry than we need; this is used to store a CrlReason
470 // at the end of the array.
471 CSSM_RETURN *statusCodes = (CSSM_RETURN*)malloc((detailCount+1) * sizeof(CSSM_RETURN));
472 statusCodes[*numStatusCodes] = 0;
473
474 const unsigned int resultmaplen = sizeof(cssmresultmap) / sizeof(resultmap_entry_t);
475 const void *keys[detailCount];
476 CFDictionaryGetKeysAndValues(detail, &keys[0], NULL);
477 for (ix = 0; ix < detailCount; ix++) {
478 CFStringRef key = (CFStringRef)keys[ix];
479 CSSM_RETURN statusCode = CSSM_OK;
480 for (unsigned int mapix = 0; mapix < resultmaplen; mapix++) {
481 CFStringRef str = (CFStringRef) cssmresultmap[mapix].checkstr;
482 if (CFStringCompare(str, key, 0) == kCFCompareEqualTo) {
483 statusCode = (CSSM_RETURN) cssmresultmap[mapix].resultcode;
484 break;
485 }
486 }
487 if (statusCode == CSSMERR_TP_CERT_REVOKED) {
488 SInt32 reason;
489 CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(detail, key);
490 if (number && CFNumberGetValue(number, kCFNumberSInt32Type, &reason)) {
491 statusCodes[*numStatusCodes] = (CSSM_RETURN)reason;
492 }
493 }
494 statusCodes[ix] = statusCode;
495 }
496
497 CFReleaseSafe(details);
498 return statusCodes;
499 }
500
501 static uint8_t convertCssmResultToPriority(CSSM_RETURN resultCode) {
502 switch (resultCode) {
503 /* explicitly not trusted */
504 case CSSMERR_TP_CERT_REVOKED:
505 case CSSMERR_APPLETP_TRUST_SETTING_DENY:
506 return 1;
507 /* failure to comply with X.509 */
508 case CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS:
509 case CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT:
510 case CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT:
511 case CSSMERR_APPLETP_INVALID_AUTHORITY_ID:
512 case CSSMERR_TP_INVALID_CERTIFICATE:
513 case CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN:
514 return 2;
515 case CSSMERR_TP_CERT_EXPIRED:
516 return 3;
517 /* doesn't chain to trusted root */
518 case CSSMERR_TP_NOT_TRUSTED:
519 case CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH:
520 return 4;
521 /* all others are policy-specific failures */
522 default:
523 return 5;
524 }
525 }
526
527 #include <libDER/oidsPriv.h>
528 #include <Security/oidscert.h>
529 static bool isSoftwareUpdateDevelopment(SecTrustRef trust) {
530 bool isPolicy = false, isEKU = false;
531 CFArrayRef policies = NULL;
532
533 /* Policy used to evaluate was SWUpdateSigning */
534 SecTrustCopyPolicies(trust, &policies);
535 if (policies) {
536 SecPolicyRef swUpdatePolicy = SecPolicyCreateAppleSWUpdateSigning();
537 if (swUpdatePolicy && CFArrayContainsValue(policies, CFRangeMake(0, CFArrayGetCount(policies)),
538 swUpdatePolicy)) {
539 isPolicy = true;
540 }
541 if (swUpdatePolicy) { CFRelease(swUpdatePolicy); }
542 CFRelease(policies);
543 }
544 if (!isPolicy) {
545 return false;
546 }
547
548 /* Only error was EKU on the leaf */
549 CFArrayRef details = SecTrustCopyFilteredDetails(trust);
550 CFIndex ix, count = CFArrayGetCount(details);
551 bool hasDisqualifyingError = false;
552 for (ix = 0; ix < count; ix++) {
553 CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
554 if (ix == 0) { // Leaf
555 if (CFDictionaryGetCount(detail) != 1 || // One error
556 CFDictionaryGetValue(detail, CFSTR("ExtendedKeyUsage")) != kCFBooleanFalse) { // kSecPolicyCheckExtendedKeyUsage
557 hasDisqualifyingError = true;
558 break;
559 }
560 } else {
561 if (CFDictionaryGetCount(detail) > 0) { // No errors on other certs
562 hasDisqualifyingError = true;
563 break;
564 }
565 }
566 }
567 CFReleaseSafe(details);
568 if (hasDisqualifyingError) {
569 return false;
570 }
571
572 /* EKU on the leaf is the Apple Development Code Signing OID */
573 SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0);
574 CSSM_DATA *fieldValue = NULL;
575 if (errSecSuccess != SecCertificateCopyFirstFieldValue(leaf, &CSSMOID_ExtendedKeyUsage, &fieldValue)) {
576 return false;
577 }
578 if (fieldValue && fieldValue->Data && fieldValue->Length == sizeof(CSSM_X509_EXTENSION)) {
579 const CSSM_X509_EXTENSION *ext = (const CSSM_X509_EXTENSION *)fieldValue->Data;
580 if (ext->format == CSSM_X509_DATAFORMAT_PARSED) {
581 const CE_ExtendedKeyUsage *ekus = (const CE_ExtendedKeyUsage *)ext->value.parsedValue;
582 if (ekus && (ekus->numPurposes == 1) && ekus->purposes[0].Data &&
583 (ekus->purposes[0].Length == CSSMOID_APPLE_EKU_CODE_SIGNING_DEV.Length) &&
584 (memcmp(ekus->purposes[0].Data, CSSMOID_APPLE_EKU_CODE_SIGNING_DEV.Data,
585 ekus->purposes[0].Length) == 0)) {
586 isEKU = true;
587 }
588 }
589 }
590 SecCertificateReleaseFirstFieldValue(leaf, &CSSMOID_ExtendedKeyUsage, fieldValue);
591 return isEKU;
592 }
593
594 //
595 // Retrieve CSSM_LEVEL TP return code
596 //
597 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
598 OSStatus SecTrustGetCssmResultCode(SecTrustRef trustRef, OSStatus *result)
599 {
600 /* bridge to support old functionality */
601 #if SECTRUST_DEPRECATION_WARNINGS
602 syslog(LOG_ERR, "WARNING: SecTrustGetCssmResultCode has been deprecated since 10.7, and will be removed in a future release. Please use SecTrustCopyProperties instead.");
603 #endif
604 if (!trustRef || !result) {
605 return errSecParam;
606 }
607
608 SecTrustResultType trustResult = kSecTrustResultInvalid;
609 (void) SecTrustGetTrustResult(trustRef, &trustResult);
610 if (trustResult == kSecTrustResultProceed || trustResult == kSecTrustResultUnspecified) {
611 if (result) { *result = 0; }
612 return errSecSuccess;
613 }
614
615 /* Development Software Update certs return a special error code when evaluated
616 * against the AppleSWUpdateSigning policy. See <rdar://27362805>. */
617 if (isSoftwareUpdateDevelopment(trustRef)) {
618 if (result) {
619 *result = CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT;
620 }
621 return errSecSuccess;
622 }
623
624 OSStatus cssmResultCode = errSecSuccess;
625 uint8_t resultCodePriority = 0xFF;
626 CFIndex ix, count = SecTrustGetCertificateCount(trustRef);
627 for (ix = 0; ix < count; ix++) {
628 unsigned int numStatusCodes;
629 CSSM_RETURN *statusCodes = NULL;
630 statusCodes = copyCssmStatusCodes(trustRef, (uint32_t)ix, &numStatusCodes);
631 if (statusCodes && numStatusCodes > 0) {
632 unsigned int statusIX;
633 for (statusIX = 0; statusIX < numStatusCodes; statusIX++) {
634 CSSM_RETURN currStatus = statusCodes[statusIX];
635 uint8_t currPriority = convertCssmResultToPriority(currStatus);
636 if (resultCodePriority > currPriority) {
637 cssmResultCode = currStatus;
638 resultCodePriority = currPriority;
639 }
640 }
641 }
642 if (statusCodes) { free(statusCodes); }
643 if (resultCodePriority == 1) { break; }
644 }
645
646 if (result) {
647 *result = cssmResultCode;
648 }
649 return errSecSuccess;
650 }
651
652 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_2, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
653 OSStatus SecTrustGetTPHandle(SecTrustRef trust, CSSM_TP_HANDLE *handle)
654 {
655 /* this function is unsupported in unified SecTrust */
656 #if SECTRUST_DEPRECATION_WARNINGS
657 syslog(LOG_ERR, "WARNING: SecTrustGetTPHandle has been deprecated since 10.7, and cannot return CSSM objects in 10.11. Please stop using it.");
658 #endif
659 if (handle) {
660 *handle = NULL;
661 }
662 return errSecServiceNotAvailable;
663 }
664
665 //
666 // Get the user's default anchor certificate set
667 //
668 /* OS X only */
669 OSStatus SecTrustCopyAnchorCertificates(CFArrayRef *anchorCertificates)
670 {
671 BEGIN_SECAPI
672
673 return SecTrustSettingsCopyUnrestrictedRoots(
674 true, true, true, /* all domains */
675 anchorCertificates);
676
677 END_SECAPI
678 }
679
680 /* We have an iOS-style SecTrustRef, but we need to return a CDSA-based SecKeyRef.
681 */
682 SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
683 {
684 SecKeyRef pubKey = NULL;
685 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, 0);
686 (void) SecCertificateCopyPublicKey(certificate, &pubKey);
687 return pubKey;
688 }
689
690 // cannot link against the new iOS SecTrust from this implementation,
691 // so there are no possible accessors for the fields of this struct
692 typedef struct __TSecTrust {
693 CFRuntimeBase _base;
694 CFArrayRef _certificates;
695 CFArrayRef _anchors;
696 CFTypeRef _policies;
697 CFArrayRef _responses;
698 CFArrayRef _SCTs;
699 CFArrayRef _trustedLogs;
700 CFDateRef _verifyDate;
701 CFTypeRef _chain;
702 SecKeyRef _publicKey;
703 CFArrayRef _details;
704 CFDictionaryRef _info;
705 CFArrayRef _exceptions;
706 SecTrustResultType _trustResult;
707 bool _anchorsOnly;
708 bool _keychainsAllowed;
709 void* _legacy_info_array;
710 void* _legacy_status_array;
711 SecTrustResultType _trustResultBeforeExceptions;
712 dispatch_queue_t _trustQueue;
713 } TSecTrust;
714
715 CFArrayRef SecTrustCopyInputCertificates(SecTrustRef trust)
716 {
717 if (!trust) { return NULL; };
718 TSecTrust *secTrust = (TSecTrust *)trust;
719 if (secTrust->_certificates) {
720 CFRetain(secTrust->_certificates);
721 }
722 return secTrust->_certificates;
723 }
724
725 CFArrayRef SecTrustCopyInputAnchors(SecTrustRef trust)
726 {
727 if (!trust) { return NULL; };
728 TSecTrust *secTrust = (TSecTrust *)trust;
729 if (secTrust->_anchors) {
730 CFRetain(secTrust->_anchors);
731 }
732 return secTrust->_anchors;
733 }
734
735 // Return the constructed certificate chain for this trust reference,
736 // making output certificates pointer-equivalent to any provided input
737 // certificates (where possible) for legacy behavioral compatibility.
738 // Caller must release this array.
739 //
740 CFArrayRef SecTrustCopyConstructedChain(SecTrustRef trust)
741 {
742 CFMutableArrayRef certChain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
743 CFIndex idx, count = SecTrustGetCertificateCount(trust);
744 for (idx=0; idx < count; idx++) {
745 SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, idx);
746 if (certificate) {
747 CFArrayAppendValue(certChain, certificate);
748 }
749 }
750 // <rdar://24393060>
751 // Some callers make the assumption that the certificates in
752 // this chain are pointer-equivalent to ones they passed to the
753 // SecTrustCreateWithCertificates function. We'll maintain that
754 // behavior here for compatibility.
755 //
756 CFArrayRef inputCertArray = SecTrustCopyInputCertificates(trust);
757 CFArrayRef inputAnchorArray = SecTrustCopyInputAnchors(trust);
758 CFIndex inputCertIdx, inputCertCount = (inputCertArray) ? CFArrayGetCount(inputCertArray) : 0;
759 CFIndex inputAnchorIdx, inputAnchorCount = (inputAnchorArray) ? CFArrayGetCount(inputAnchorArray) : 0;
760 for (idx=0; idx < count; idx++) {
761 SecCertificateRef tmpCert = (SecCertificateRef) CFArrayGetValueAtIndex(certChain, idx);
762 if (tmpCert) {
763 SecCertificateRef matchCert = NULL;
764 for (inputCertIdx=0; inputCertIdx < inputCertCount && !matchCert; inputCertIdx++) {
765 SecCertificateRef inputCert = (SecCertificateRef) CFArrayGetValueAtIndex(inputCertArray, inputCertIdx);
766 if (inputCert && CFEqual(inputCert, tmpCert)) {
767 matchCert = inputCert;
768 }
769 }
770 for (inputAnchorIdx=0; inputAnchorIdx < inputAnchorCount && !matchCert; inputAnchorIdx++) {
771 SecCertificateRef inputAnchor = (SecCertificateRef) CFArrayGetValueAtIndex(inputAnchorArray, inputAnchorIdx);
772 if (inputAnchor && CFEqual(inputAnchor, tmpCert)) {
773 matchCert = inputAnchor;
774 }
775 }
776 if (matchCert) {
777 CFArraySetValueAtIndex(certChain, idx, matchCert);
778 }
779 }
780 }
781 if (inputCertArray) {
782 CFRelease(inputCertArray);
783 }
784 if (inputAnchorArray) {
785 CFRelease(inputAnchorArray);
786 }
787 return certChain;
788 }
789
790 //
791 // Here is where backward compatibility gets ugly. CSSM_TP_APPLE_EVIDENCE_INFO does not exist
792 // in the unified SecTrust world. Unfortunately, some clients are still calling legacy APIs
793 // (e.g. SecTrustGetResult) and grubbing through the info for StatusBits and StatusCodes.
794 // SecTrustGetEvidenceInfo builds the legacy evidence info structure as needed, and returns
795 // a pointer to it. The evidence data is allocated here and set in the _legacy_* fields
796 // of the TSecTrust; the trust object subsequently owns it. The returned pointer is expected
797 // to be valid for the lifetime of the SecTrustRef, or until the trust parameters are changed,
798 // which would force re-evaluation.
799 //
800 static CSSM_TP_APPLE_EVIDENCE_INFO *
801 SecTrustGetEvidenceInfo(SecTrustRef trust)
802 {
803 TSecTrust *secTrust = (TSecTrust *)trust;
804 if (!secTrust) {
805 return NULL;
806 }
807 if (secTrust->_trustResult != kSecTrustResultInvalid &&
808 secTrust->_legacy_info_array) {
809 // we've already got valid evidence info, return it now.
810 return (CSSM_TP_APPLE_EVIDENCE_INFO *)secTrust->_legacy_info_array;
811 }
812
813 // Getting the count implicitly evaluates the chain if necessary.
814 CFIndex idx, count = SecTrustGetCertificateCount(trust);
815 CFArrayRef inputCertArray = SecTrustCopyInputCertificates(trust);
816 CFArrayRef inputAnchorArray = SecTrustCopyInputAnchors(trust);
817 CFIndex inputCertIdx, inputCertCount = (inputCertArray) ? CFArrayGetCount(inputCertArray) : 0;
818 CFIndex inputAnchorIdx, inputAnchorCount = (inputAnchorArray) ? CFArrayGetCount(inputAnchorArray) : 0;
819
820 CSSM_TP_APPLE_EVIDENCE_INFO *infoArray = (CSSM_TP_APPLE_EVIDENCE_INFO *)calloc(count, sizeof(CSSM_TP_APPLE_EVIDENCE_INFO));
821 CSSM_RETURN *statusArray = NULL;
822 unsigned int numStatusCodes = 0;
823
824 // Set status codes for each certificate in the constructed chain
825 for (idx=0; idx < count; idx++) {
826 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, idx);
827 if (!cert) {
828 continue;
829 }
830 CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &infoArray[idx];
831
832 /* first the booleans (StatusBits flags) */
833 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
834 if (secTrust->_verifyDate) {
835 now = CFDateGetAbsoluteTime(secTrust->_verifyDate);
836 }
837 CFAbsoluteTime na = SecCertificateNotValidAfter(cert);
838 if (na < now) {
839 evInfo->StatusBits |= CSSM_CERT_STATUS_EXPIRED;
840 }
841 CFAbsoluteTime nb = SecCertificateNotValidBefore(cert);
842 if (nb > now) {
843 evInfo->StatusBits |= CSSM_CERT_STATUS_NOT_VALID_YET;
844 }
845 for (inputAnchorIdx=0; inputAnchorIdx < inputAnchorCount; inputAnchorIdx++) {
846 SecCertificateRef inputAnchor = (SecCertificateRef) CFArrayGetValueAtIndex(inputAnchorArray, inputAnchorIdx);
847 if (inputAnchor && CFEqual(inputAnchor, cert)) {
848 evInfo->StatusBits |= CSSM_CERT_STATUS_IS_IN_ANCHORS;
849 break;
850 }
851 }
852 for (inputCertIdx=0; inputCertIdx < inputCertCount; inputCertIdx++) {
853 SecCertificateRef inputCert = (SecCertificateRef) CFArrayGetValueAtIndex(inputCertArray, inputCertIdx);
854 if (inputCert && CFEqual(inputCert, cert)) {
855 evInfo->StatusBits |= CSSM_CERT_STATUS_IS_IN_INPUT_CERTS;
856 break;
857 }
858 }
859
860 /* See if there are trust settings for this certificate. */
861 CFStringRef hashStr = SecTrustSettingsCertHashStrFromCert(cert);
862 bool foundMatch = false;
863 bool foundAny = false;
864 CSSM_RETURN *errors = NULL;
865 uint32 errorCount = 0;
866 OSStatus status = 0;
867 SecTrustSettingsDomain foundDomain = kSecTrustSettingsDomainUser;
868 SecTrustSettingsResult foundResult = kSecTrustSettingsResultInvalid;
869 bool isSelfSigned = false;
870 if ((count - 1) == idx) {
871 // Only the last cert in the chain needs to be considered
872 Boolean selfSigned;
873 status = SecCertificateIsSelfSigned(cert, &selfSigned);
874 isSelfSigned = (status) ? false : ((selfSigned) ? true : false);
875 if (isSelfSigned) {
876 evInfo->StatusBits |= CSSM_CERT_STATUS_IS_ROOT;
877 }
878 }
879 // STU: rdar://25554967
880 // %%% need to get policyOID, policyString, and keyUsage here!
881
882 status = SecTrustSettingsEvaluateCert(
883 hashStr, /* certHashStr */
884 NULL, /* policyOID (optional) */
885 NULL, /* policyString (optional) */
886 0, /* policyStringLen */
887 0, /* keyUsage */
888 isSelfSigned, /* isRootCert */
889 &foundDomain, /* foundDomain */
890 &errors, /* allowedErrors -- MUST FREE */
891 &errorCount, /* numAllowedErrors */
892 &foundResult, /* resultType */
893 &foundMatch, /* foundMatchingEntry */
894 &foundAny); /* foundAnyEntry */
895
896 if (status == errSecSuccess) {
897 if (foundMatch) {
898 switch (foundResult) {
899 case kSecTrustSettingsResultTrustRoot:
900 case kSecTrustSettingsResultTrustAsRoot:
901 /* these two can be disambiguated by IS_ROOT */
902 evInfo->StatusBits |= CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST;
903 break;
904 case kSecTrustSettingsResultDeny:
905 evInfo->StatusBits |= CSSM_CERT_STATUS_TRUST_SETTINGS_DENY;
906 break;
907 case kSecTrustSettingsResultUnspecified:
908 case kSecTrustSettingsResultInvalid:
909 default:
910 break;
911 }
912 }
913 }
914 if (errors) {
915 free(errors);
916 }
917 if (hashStr) {
918 CFRelease(hashStr);
919 }
920
921 unsigned int numCodes=0;
922 CSSM_RETURN *statusCodes = copyCssmStatusCodes(trust, (unsigned int)idx, &numCodes);
923 if (statusCodes) {
924 // Realloc space for these status codes at end of our status codes block.
925 // Two important things to note:
926 // 1. the actual length is numCodes+1 because copyCssmStatusCodes
927 // allocates one more element at the end for the CrlReason value.
928 // 2. realloc may cause the pointer to move, which means we will
929 // need to fix up the StatusCodes fields after we're done with this loop.
930 unsigned int totalStatusCodes = numStatusCodes + numCodes + 1;
931 statusArray = (CSSM_RETURN *)realloc(statusArray, totalStatusCodes * sizeof(CSSM_RETURN));
932 evInfo->StatusCodes = &statusArray[numStatusCodes];
933 evInfo->NumStatusCodes = numCodes;
934 // Copy the new codes (plus one) into place
935 for (unsigned int cpix = 0; cpix <= numCodes; cpix++) {
936 evInfo->StatusCodes[cpix] = statusCodes[cpix];
937 }
938 numStatusCodes = totalStatusCodes;
939 free(statusCodes);
940 }
941
942 if(evInfo->StatusBits & (CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST |
943 CSSM_CERT_STATUS_TRUST_SETTINGS_DENY |
944 CSSM_CERT_STATUS_TRUST_SETTINGS_IGNORED_ERROR)) {
945 /* Something noteworthy happened involving TrustSettings */
946 uint32 whichDomain = 0;
947 switch(foundDomain) {
948 case kSecTrustSettingsDomainUser:
949 whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER;
950 break;
951 case kSecTrustSettingsDomainAdmin:
952 whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN;
953 break;
954 case kSecTrustSettingsDomainSystem:
955 whichDomain = CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM;
956 break;
957 }
958 evInfo->StatusBits |= whichDomain;
959 }
960
961 /* index into raw cert group or AnchorCerts depending on IS_IN_ANCHORS */
962 //evInfo->Index = certInfo->index();
963 /* nonzero if cert came from a DLDB */
964 //evInfo->DlDbHandle = certInfo->dlDbHandle();
965 //evInfo->UniqueRecord = certInfo->uniqueRecord();
966 }
967
968 // Now that all the status codes have been allocated in a contiguous block,
969 // refresh the StatusCodes pointer in each array element.
970 numStatusCodes = 0;
971 for (idx=0; idx < count; idx++) {
972 CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &infoArray[idx];
973 evInfo->StatusCodes = &statusArray[numStatusCodes];
974 numStatusCodes += evInfo->NumStatusCodes + 1;
975 }
976
977 secTrust->_legacy_info_array = infoArray;
978 secTrust->_legacy_status_array = statusArray;
979
980 if (inputCertArray) {
981 CFRelease(inputCertArray);
982 }
983 if (inputAnchorArray) {
984 CFRelease(inputAnchorArray);
985 }
986
987 return (CSSM_TP_APPLE_EVIDENCE_INFO *)secTrust->_legacy_info_array;
988 }
989
990 CFArrayRef SecTrustCopyProperties(SecTrustRef trust) {
991 /* OS X creates a completely different structure with one dictionary for each certificate */
992 CFIndex ix, count = SecTrustGetCertificateCount(trust);
993
994 CFMutableArrayRef properties = CFArrayCreateMutable(kCFAllocatorDefault, count,
995 &kCFTypeArrayCallBacks);
996
997 for (ix = 0; ix < count; ix++) {
998 CFMutableDictionaryRef certDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
999 &kCFTypeDictionaryValueCallBacks);
1000 /* Populate the certificate title */
1001 SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, ix);
1002 if (cert) {
1003 CFStringRef subjectSummary = SecCertificateCopySubjectSummary(cert);
1004 if (subjectSummary) {
1005 CFDictionaryAddValue(certDict, kSecPropertyTypeTitle, subjectSummary);
1006 CFRelease(subjectSummary);
1007 }
1008 }
1009
1010 /* Populate a revocation reason if the cert was revoked */
1011 unsigned int numStatusCodes;
1012 CSSM_RETURN *statusCodes = NULL;
1013 statusCodes = copyCssmStatusCodes(trust, (uint32_t)ix, &numStatusCodes);
1014 if (statusCodes) {
1015 int32_t reason = statusCodes[numStatusCodes]; // stored at end of status codes array
1016 if (reason > 0) {
1017 CFNumberRef cfreason = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &reason);
1018 if (cfreason) {
1019 CFDictionarySetValue(certDict, kSecTrustRevocationReason, cfreason);
1020 CFRelease(cfreason);
1021 }
1022 }
1023 free(statusCodes);
1024 }
1025
1026 /* Populate the error in the leaf dictionary */
1027 if (ix == 0) {
1028 OSStatus error = errSecSuccess;
1029 (void)SecTrustGetCssmResultCode(trust, &error);
1030 CFStringRef errorStr = SecCopyErrorMessageString(error, NULL);
1031 if (errorStr) {
1032 CFDictionarySetValue(certDict, kSecPropertyTypeError, errorStr);
1033 CFRelease(errorStr);
1034 }
1035 }
1036
1037 CFArrayAppendValue(properties, certDict);
1038 CFRelease(certDict);
1039 }
1040
1041 return properties;
1042 }
1043
1044 /* deprecated in 10.5 */
1045 OSStatus SecTrustGetCSSMAnchorCertificates(const CSSM_DATA **cssmAnchors,
1046 uint32 *cssmAnchorCount)
1047 {
1048 /* this function is unsupported in unified SecTrust */
1049 #if SECTRUST_DEPRECATION_WARNINGS
1050 syslog(LOG_ERR, "WARNING: SecTrustGetCSSMAnchorCertificates has been deprecated since 10.5, and cannot return CSSM objects in 10.11. Please stop using it.");
1051 #endif
1052 if (cssmAnchors) {
1053 *cssmAnchors = NULL;
1054 }
1055 if (cssmAnchorCount) {
1056 *cssmAnchorCount = 0;
1057 }
1058 return errSecServiceNotAvailable;
1059 }
1060
1061
1062 //
1063 // Get and set user trust settings. Deprecated in 10.5.
1064 // User Trust getter, deprecated, works as it always has.
1065 //
1066 OSStatus SecTrustGetUserTrust(SecCertificateRef certificate,
1067 SecPolicyRef policy, SecTrustUserSetting *trustSetting)
1068 {
1069 /* this function is unsupported in unified SecTrust */
1070 #if SECTRUST_DEPRECATION_WARNINGS
1071 syslog(LOG_ERR, "WARNING: SecTrustGetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
1072 #endif
1073 return errSecServiceNotAvailable;
1074 }
1075
1076 //
1077 // The public setter, also deprecated; it maps to the appropriate
1078 // Trust Settings call if possible, else throws errSecUnimplemented.
1079 //
1080 OSStatus SecTrustSetUserTrust(SecCertificateRef certificate,
1081 SecPolicyRef policy, SecTrustUserSetting trustSetting)
1082 {
1083 /* this function is unsupported in unified SecTrust */
1084 #if SECTRUST_DEPRECATION_WARNINGS
1085 syslog(LOG_ERR, "WARNING: SecTrustSetUserTrust has been deprecated since 10.5, and does nothing in 10.11. Please stop using it.");
1086 #endif
1087 return errSecServiceNotAvailable;
1088 }
1089
1090 //
1091 // This one is the now-private version of what SecTrustSetUserTrust() used to
1092 // be. The public API can no longer manipulate User Trust settings, only
1093 // view them.
1094 //
1095 OSStatus SecTrustSetUserTrustLegacy(SecCertificateRef certificate,
1096 SecPolicyRef policy, SecTrustUserSetting trustSetting)
1097 {
1098 /* this function is unsupported in unified SecTrust */
1099 #if SECTRUST_DEPRECATION_WARNINGS
1100 syslog(LOG_ERR, "WARNING: SecTrustSetUserTrustLegacy does nothing in 10.11. Please stop using it.");
1101 #endif
1102 return errSecServiceNotAvailable;
1103 }