void debugCallback( CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { int i = 0; printf("Debug callback: %s\n", CFStringToCString(name)); if (!userInfo) return; CFIndex count = CFDictionaryGetCount(userInfo); const void *keys[count]; const void *values[count]; CFDictionaryGetKeysAndValues(userInfo, keys, values); for(i = 0; i < count; i++) { printf("For i=%d, key: %s\n", i, CFStringToCString((CFStringRef)keys[i])); } }
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); } }
OSStatus SecAccessCreateWithTrustedApplications(CFStringRef trustedApplicationsPListPath, CFStringRef accessLabel, Boolean allowAny, SecAccessRef* returnedAccess) { OSStatus err = errSecSuccess; SecAccessRef accessToReturn=nil; CFMutableArrayRef trustedApplications=nil; if (!allowAny) // use default access ("confirm access") { // make an exception list of applications you want to trust, // which are allowed to access the item without requiring user confirmation SecTrustedApplicationRef myself=NULL, someOther=NULL; CFArrayRef trustedAppListFromBundle=NULL; trustedApplications=CFArrayCreateMutable(kCFAllocatorDefault,0,&kCFTypeArrayCallBacks); err = SecTrustedApplicationCreateFromPath(NULL, &myself); if (!err) CFArrayAppendValue(trustedApplications,myself); CFURLRef url = CFURLCreateWithFileSystemPath(NULL, trustedApplicationsPListPath, kCFURLPOSIXPathStyle, 0); CFStringRef leafStr = NULL; leafStr = CFURLCopyLastPathComponent(url); CFURLRef bndlPathURL = NULL; bndlPathURL = CFURLCreateCopyDeletingLastPathComponent(NULL, url); CFStringRef bndlPath = NULL; bndlPath = CFURLCopyFileSystemPath(bndlPathURL, kCFURLPOSIXPathStyle); trustedAppListFromBundle=copyTrustedAppListFromBundle(bndlPath, leafStr); if ( leafStr ) CFRelease(leafStr); if ( bndlPath ) CFRelease(bndlPath); if ( url ) CFRelease(url); if ( bndlPathURL ) CFRelease(bndlPathURL); if (trustedAppListFromBundle) { CFIndex ix,top; char buffer[MAXPATHLEN]; top = CFArrayGetCount(trustedAppListFromBundle); for (ix=0;ix<top;ix++) { CFStringRef filename = (CFStringRef)CFArrayGetValueAtIndex(trustedAppListFromBundle,ix); CFIndex stringLength = CFStringGetLength(filename); CFIndex usedBufLen; if (stringLength != CFStringGetBytes(filename,CFRangeMake(0,stringLength),kCFStringEncodingUTF8,0, false,(UInt8 *)&buffer,MAXPATHLEN, &usedBufLen)) break; buffer[usedBufLen] = 0; // // Support specification of trusted applications by either // a full pathname or a code requirement string. // if (buffer[0]=='/') { err = SecTrustedApplicationCreateFromPath(buffer,&someOther); } else { char *buf = NULL; CFStringRef reqStr = filename; CFArrayRef descArray = CFStringCreateArrayBySeparatingStrings(NULL, reqStr, CFSTR("\"")); if (descArray && (CFArrayGetCount(descArray) > 1)) { CFStringRef descStr = (CFStringRef) CFArrayGetValueAtIndex(descArray, 1); if (descStr) buf = CFStringToCString(descStr); } SecRequirementRef reqRef = NULL; err = SecRequirementCreateWithString(reqStr, kSecCSDefaultFlags, &reqRef); if (!err) err = SecTrustedApplicationCreateFromRequirement((const char *)buf, reqRef, &someOther); if (buf) free(buf); CFReleaseSafe(reqRef); CFReleaseSafe(descArray); } if (!err) CFArrayAppendValue(trustedApplications,someOther); if (someOther) CFReleaseNull(someOther); } CFRelease(trustedAppListFromBundle); } } err = SecAccessCreate((CFStringRef)accessLabel, (CFArrayRef)trustedApplications, &accessToReturn); if (!err) { if (allowAny) // change access to be wide-open for decryption ("always allow access") { // get the access control list for decryption operations CFArrayRef aclList=nil; err = SecAccessCopySelectedACLList(accessToReturn, CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList); if (!err) { // get the first entry in the access control list SecACLRef aclRef=(SecACLRef)CFArrayGetValueAtIndex(aclList, 0); CFArrayRef appList=nil; CFStringRef promptDescription=nil; CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector; err = SecACLCopySimpleContents(aclRef, &appList, &promptDescription, &promptSelector); // modify the default ACL to not require the passphrase, and have a nil application list promptSelector.flags &= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE; err = SecACLSetSimpleContents(aclRef, NULL, promptDescription, &promptSelector); if (appList) CFRelease(appList); if (promptDescription) CFRelease(promptDescription); } } } *returnedAccess = accessToReturn; return err; }