-#if !SECTRUST_OSX
-OSStatus SecTrustCreateWithCertificates(
- CFTypeRef certificates,
- CFTypeRef policies,
- SecTrustRef *trustRef)
-{
- BEGIN_SECAPI
- Required(trustRef);
- *trustRef = (new Trust(certificates, policies))->handle();
- END_SECAPI
-}
-#endif
-
-#if !SECTRUST_OSX
-OSStatus
-SecTrustSetPolicies(SecTrustRef trustRef, CFTypeRef policies)
-{
- BEGIN_SECAPI
- Trust::required(trustRef)->policies(policies);
- END_SECAPI
-}
-#endif
-
-#if SECTRUST_OSX
-typedef struct {
- SecTrustOptionFlags flags;
- CFIndex certIX;
- SecTrustRef trustRef;
- CFMutableDictionaryRef filteredException;
- CFDictionaryRef oldException;
-} SecExceptionFilterContext;
-
-#if 0
-//%%%FIXME SecCFWrappers produces some conflicting definitions on OSX
-#include <utilities/SecCFWrappers.h>
-#else
-// inline function from SecCFWrappers.h
-static inline char *CFStringToCString(CFStringRef inStr)
-{
- if (!inStr)
- return (char *)strdup("");
- CFRetain(inStr); // compensate for release on exit
-
- // need to extract into buffer
- CFIndex length = CFStringGetLength(inStr); // in 16-bit character units
- size_t len = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
- char *buffer = (char *)malloc(len); // pessimistic
- if (!CFStringGetCString(inStr, buffer, len, kCFStringEncodingUTF8))
- buffer[0] = 0;
-
- CFRelease(inStr);
- return buffer;
-}
-#endif
-
-static void
-filter_exception(const void *key, const void *value, void *context)
-{
- SecExceptionFilterContext *ctx = (SecExceptionFilterContext *)context;
- if (!ctx) { return; }
-
- SecTrustOptionFlags options = ctx->flags;
- CFMutableDictionaryRef filteredException = ctx->filteredException;
- CFStringRef keystr = (CFStringRef)key;
-
- if (ctx->oldException && CFDictionaryContainsKey(ctx->oldException, key)) {
- // Keep existing exception in filtered dictionary, regardless of options
- CFDictionaryAddValue(filteredException, key, CFDictionaryGetValue(ctx->oldException, key));
- return;
- }
-
- bool allowed = false;
-
- if (CFEqual(keystr, CFSTR("SHA1Digest"))) {
- allowed = true; // this key is informational and always permitted
- }
- else if (CFEqual(keystr, CFSTR("NotValidBefore"))) {
- allowed = ((options & kSecTrustOptionAllowExpired) != 0);
- }
- else if (CFEqual(keystr, CFSTR("ValidLeaf"))) {
- allowed = ((options & kSecTrustOptionAllowExpired) != 0);
- }
- else if (CFEqual(keystr, CFSTR("ValidIntermediates"))) {
- allowed = ((options & kSecTrustOptionAllowExpired) != 0);
- }
- else if (CFEqual(keystr, CFSTR("ValidRoot"))) {
- if (((options & kSecTrustOptionAllowExpired) != 0) ||
- ((options & kSecTrustOptionAllowExpiredRoot) != 0)) {
- allowed = true;
- }
- }
- else if (CFEqual(keystr, CFSTR("AnchorTrusted"))) {
- bool implicitAnchors = ((options & kSecTrustOptionImplicitAnchors) != 0);
- // Implicit anchors option only filters exceptions for self-signed certs
- if (implicitAnchors && ctx->trustRef &&
- (ctx->certIX < SecTrustGetCertificateCount(ctx->trustRef))) {
- Boolean isSelfSigned = false;
- SecCertificateRef cert = SecTrustGetCertificateAtIndex(ctx->trustRef, ctx->certIX);
- if (cert && (errSecSuccess == SecCertificateIsSelfSigned(cert, &isSelfSigned)) &&
- isSelfSigned) {
- allowed = true;
- }
- }
- }
- else if (CFEqual(keystr, CFSTR("KeyUsage")) ||
- CFEqual(keystr, CFSTR("ExtendedKeyUsage")) ||
- CFEqual(keystr, CFSTR("BasicConstraints")) ||
- CFEqual(keystr, CFSTR("NonEmptySubject")) ||
- CFEqual(keystr, CFSTR("IdLinkage"))) {
- // Cannot override these exceptions
- allowed = false;
- }
- else {
- // Unhandled exceptions should not be overridden,
- // but we want to know which ones we're missing
- char *cstr = CFStringToCString(keystr);
- syslog(LOG_ERR, "Unfiltered exception: %s", (cstr) ? cstr : "<NULL>");
- if (cstr) { free(cstr); }
- allowed = false;
- }
-
- if (allowed) {
- CFDictionaryAddValue(filteredException, key, value);
- }
-}
-
-#endif
-
-/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */
-OSStatus
-SecTrustSetOptions(SecTrustRef trustRef, SecTrustOptionFlags options)
-{
-#if !SECTRUST_OSX
- BEGIN_SECAPI
- CSSM_APPLE_TP_ACTION_DATA actionData = {
- CSSM_APPLE_TP_ACTION_VERSION,
- (CSSM_APPLE_TP_ACTION_FLAGS)options
- };
- Trust *trust = Trust::required(trustRef);
- CFDataRef actionDataRef = CFDataCreate(NULL,
- (const UInt8 *)&actionData,
- (CFIndex)sizeof(CSSM_APPLE_TP_ACTION_DATA));
- trust->action(CSSM_TP_ACTION_DEFAULT);
- trust->actionData(actionDataRef);
- if (actionDataRef) CFRelease(actionDataRef);
- END_SECAPI
-#else
- /* bridge to support API functionality for legacy callers */
- OSStatus status = errSecSuccess;
- CFDataRef encodedExceptions = SecTrustCopyExceptions(trustRef);
- CFArrayRef exceptions = NULL,
- oldExceptions = SecTrustGetTrustExceptionsArray(trustRef);
-
- if (encodedExceptions) {
- exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault,
- encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
- CFRelease(encodedExceptions);
- encodedExceptions = NULL;
- }
-
- if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
- CFRelease(exceptions);
- exceptions = NULL;
- }
-
- if (oldExceptions && exceptions &&
- CFArrayGetCount(oldExceptions) > CFArrayGetCount(exceptions)) {
- oldExceptions = NULL;
- }
-
- /* verify both exceptions are for the same leaf */
- if (oldExceptions && exceptions && CFArrayGetCount(oldExceptions) > 0) {
- CFDictionaryRef oldLeafExceptions = (CFDictionaryRef)CFArrayGetValueAtIndex(oldExceptions, 0);
- CFDictionaryRef leafExceptions = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, 0);
- CFDataRef oldDigest = (CFDataRef)CFDictionaryGetValue(oldLeafExceptions, CFSTR("SHA1Digest"));
- CFDataRef digest = (CFDataRef)CFDictionaryGetValue(leafExceptions, CFSTR("SHA1Digest"));
- if (!oldDigest || !digest || !CFEqual(oldDigest, digest)) {
- oldExceptions = NULL;
- }
- }
-
- /* add only those exceptions which are allowed by the supplied options */
- if (exceptions) {
- CFMutableArrayRef filteredExceptions = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- CFIndex i, exceptionCount = (filteredExceptions) ? CFArrayGetCount(exceptions) : 0;
-
- for (i = 0; i < exceptionCount; ++i) {
- CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, i);
- CFDictionaryRef oldException = NULL;
- if (oldExceptions && i < CFArrayGetCount(oldExceptions)) {
- oldException = (CFDictionaryRef)CFArrayGetValueAtIndex(oldExceptions, i);
- }
- CFMutableDictionaryRef filteredException = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- if (exception && filteredException) {
- SecExceptionFilterContext filterContext = { options, i, trustRef, filteredException, oldException };
- CFDictionaryApplyFunction(exception, filter_exception, &filterContext);
- CFArrayAppendValue(filteredExceptions, filteredException);
- CFRelease(filteredException);
- }
- }
-
- if (filteredExceptions) {
- CFIndex filteredCount = CFArrayGetCount(filteredExceptions);
- /* remove empty trailing entries to match iOS behavior */
- for (i = filteredCount; i-- > 1;) {
- CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(filteredExceptions, i);
- if (CFDictionaryGetCount(exception) == 0) {
- CFArrayRemoveValueAtIndex(filteredExceptions, i);
- } else {
- break;
- }
- }
- encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
- filteredExceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
- CFRelease(filteredExceptions);
-
- SecTrustSetExceptions(trustRef, encodedExceptions);
- CFRelease(encodedExceptions);
- }
- CFRelease(exceptions);
- }
-
-#if SECTRUST_DEPRECATION_WARNINGS
- bool displayModifyMsg = false;
- bool displayNetworkMsg = false;
- bool displayPolicyMsg = false;
- const char *baseMsg = "WARNING: SecTrustSetOptions called with";
- const char *modifyMsg = "Use SecTrustSetExceptions and SecTrustCopyExceptions to modify default trust results.";
- const char *networkMsg = "Use SecTrustSetNetworkFetchAllowed to specify whether missing certificates can be fetched from the network.";
- const char *policyMsg = "Use SecPolicyCreateRevocation to specify revocation policy requirements.";
-
- if (options & kSecTrustOptionAllowExpired) {
- syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionAllowExpired");
- displayModifyMsg = true;
- }
- if (options & kSecTrustOptionAllowExpiredRoot) {
- syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionAllowExpiredRoot");
- displayModifyMsg = true;
- }
- if (options & kSecTrustOptionFetchIssuerFromNet) {
- syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionFetchIssuerFromNet");
- displayNetworkMsg = true;
- }
- if (options & kSecTrustOptionRequireRevPerCert) {
- syslog(LOG_ERR, "%s %s.", baseMsg, "kSecTrustOptionRequireRevPerCert");
- displayPolicyMsg = true;
- }
- if (displayModifyMsg || displayNetworkMsg || displayPolicyMsg) {
- syslog(LOG_ERR, "%s %s %s",
- (displayModifyMsg) ? modifyMsg : "",
- (displayNetworkMsg) ? networkMsg : "",
- (displayPolicyMsg) ? policyMsg : "");
- }
-#endif
-
- return status;
-
-#endif
-}
-