-#endif
-
-#if !SECTRUST_OSX
-static CFStringRef kSecCertificateDetailSHA1Digest = CFSTR("SHA1Digest");
-static CFStringRef kSecCertificateDetailStatusCodes = CFSTR("StatusCodes");
-
-static void
-_AppendStatusCode(CFMutableArrayRef array, OSStatus statusCode)
-{
- if (!array)
- return;
- SInt32 num = statusCode;
- CFNumberRef numRef = CFNumberCreate(NULL, kCFNumberSInt32Type, &num);
- if (!numRef)
- return;
- CFArrayAppendValue(array, numRef);
- CFRelease(numRef);
-}
-#endif
-
-#if !SECTRUST_OSX
-CFArrayRef SecTrustCopyDetails(SecTrustRef trust)
-{
- // This function returns an array of dictionaries, one per certificate,
- // holding status info for each certificate in the evaluated chain.
- //
- CFIndex count, chainLen = 0;
- CFArrayRef certChain = NULL;
- CFMutableArrayRef details = NULL;
- CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
- OSStatus __secapiresult = errSecSuccess;
- try {
- Trust *trustObj = Trust::required(trust);
- if (trustObj->result() == kSecTrustResultInvalid) {
- trustObj->evaluate();
- if (trustObj->result() == kSecTrustResultInvalid)
- MacOSError::throwMe(errSecTrustNotAvailable);
- }
- trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain));
- }
- catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
- catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
- catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
- catch (...) { __secapiresult=errSecInternalComponent; }
-
- if (certChain) {
- chainLen = CFArrayGetCount(certChain);
- CFRelease(certChain);
- }
- if (statusChain) {
- details = CFArrayCreateMutable(NULL, chainLen, &kCFTypeArrayCallBacks);
- for (count = 0; count < chainLen; count++) {
- CFMutableDictionaryRef certDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
- 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- CFMutableArrayRef statusCodes = CFArrayCreateMutable(kCFAllocatorDefault,
- 0, &kCFTypeArrayCallBacks);
- CSSM_TP_APPLE_EVIDENCE_INFO *evInfo = &statusChain[count];
- CSSM_TP_APPLE_CERT_STATUS statBits = evInfo->StatusBits;
-
- // translate status bits
- if (statBits & CSSM_CERT_STATUS_EXPIRED)
- _AppendStatusCode(statusCodes, errSecCertificateExpired);
- if (statBits & CSSM_CERT_STATUS_NOT_VALID_YET)
- _AppendStatusCode(statusCodes, errSecCertificateNotValidYet);
- if (statBits & CSSM_CERT_STATUS_TRUST_SETTINGS_DENY)
- _AppendStatusCode(statusCodes, errSecTrustSettingDeny);
-
- // translate status codes
- unsigned int i;
- for (i = 0; i < evInfo->NumStatusCodes; i++) {
- CSSM_RETURN scode = evInfo->StatusCodes[i];
- _AppendStatusCode(statusCodes, (OSStatus)scode);
- }
-
- CFDictionarySetValue(certDict, kSecCertificateDetailStatusCodes, statusCodes);
- CFRelease(statusCodes);
- CFArrayAppendValue(details, certDict);
- CFRelease(certDict);
- }
- }
- return details;
-}
-#endif
-
-#if !SECTRUST_OSX
-static CFDictionaryRef SecTrustGetExceptionForCertificateAtIndex(SecTrustRef trust, CFIndex ix)
-{
- CFArrayRef exceptions = NULL;
- OSStatus __secapiresult = errSecSuccess;
- try {
- exceptions = Trust::required(trust)->exceptions();
- }
- catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
- catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
- catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
- catch (...) { __secapiresult=errSecInternalComponent; }
-
- if (!exceptions || ix >= CFArrayGetCount(exceptions))
- return NULL;
- CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
- if (CFGetTypeID(exception) != CFDictionaryGetTypeID())
- return NULL;
-
- SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
- if (!certificate)
- return NULL;
-
- /* If the exception contains the current certificate's sha1Digest in the
- kSecCertificateDetailSHA1Digest key then we use it otherwise we ignore it. */
- CFDataRef sha1Digest = SecCertificateGetSHA1Digest(certificate);
- CFTypeRef digestValue = CFDictionaryGetValue(exception, kSecCertificateDetailSHA1Digest);
- if (!digestValue || !CFEqual(sha1Digest, digestValue))
- exception = NULL;
-
- return exception;
-}
-#endif
-
-#if !SECTRUST_OSX
-static void SecTrustCheckException(const void *key, const void *value, void *context)
-{
- struct SecTrustCheckExceptionContext *cec = (struct SecTrustCheckExceptionContext *)context;
- if (cec->exception) {
- CFTypeRef exceptionValue = CFDictionaryGetValue(cec->exception, key);
- if (!exceptionValue || !CFEqual(value, exceptionValue)) {
- cec->exceptionNotFound = true;
- }
- } else {
- cec->exceptionNotFound = true;
- }
-}
-#endif
-
-#if !SECTRUST_OSX
-/* new in 10.9 */
-CFDataRef SecTrustCopyExceptions(SecTrustRef trust)
-{
- CFArrayRef details = SecTrustCopyDetails(trust);
- CFIndex pathLength = details ? CFArrayGetCount(details) : 0;
- CFMutableArrayRef exceptions = CFArrayCreateMutable(kCFAllocatorDefault,
- pathLength, &kCFTypeArrayCallBacks);
- CFIndex ix;
- for (ix = 0; ix < pathLength; ++ix) {
- CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix);
- CFIndex detailCount = CFDictionaryGetCount(detail);
- CFMutableDictionaryRef exception;
- if (ix == 0 || detailCount > 0) {
- exception = CFDictionaryCreateMutableCopy(kCFAllocatorDefault,
- detailCount + 1, detail);
- SecCertificateRef certificate = SecTrustGetCertificateAtIndex(trust, ix);
- CFDataRef digest = SecCertificateGetSHA1Digest(certificate);
- if (digest) {
- CFDictionaryAddValue(exception, kSecCertificateDetailSHA1Digest, digest);
- }
- } else {
- /* Add empty exception dictionaries for non leaf certs which have no exceptions
- * to save space.
- */
- exception = (CFMutableDictionaryRef)CFDictionaryCreate(kCFAllocatorDefault,
- NULL, NULL, 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- }
- CFArrayAppendValue(exceptions, exception);
- CFReleaseNull(exception);
- }
- CFReleaseSafe(details);
-
- /* Remove any trailing empty dictionaries to save even more space (we skip the leaf
- since it will never be empty). */
- for (ix = pathLength; ix-- > 1;) {
- CFDictionaryRef exception = (CFDictionaryRef)CFArrayGetValueAtIndex(exceptions, ix);
- if (CFDictionaryGetCount(exception) == 0) {
- CFArrayRemoveValueAtIndex(exceptions, ix);
- } else {
- break;
- }
- }
-
- CFDataRef encodedExceptions = CFPropertyListCreateData(kCFAllocatorDefault,
- exceptions, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
- CFRelease(exceptions);
-
- return encodedExceptions;
-}
-#endif
-
-#if !SECTRUST_OSX
-/* new in 10.9 */
-bool SecTrustSetExceptions(SecTrustRef trust, CFDataRef encodedExceptions)
-{
- CFArrayRef exceptions = NULL;
-
- if (NULL != encodedExceptions) {
- exceptions = (CFArrayRef)CFPropertyListCreateWithData(kCFAllocatorDefault,
- encodedExceptions, kCFPropertyListImmutable, NULL, NULL);
- }
-
- if (exceptions && CFGetTypeID(exceptions) != CFArrayGetTypeID()) {
- CFRelease(exceptions);
- exceptions = NULL;
- }
-
- OSStatus __secapiresult = errSecSuccess;
- try {
- /* Exceptions are being set or cleared, we'll need to re-evaluate trust either way. */
- Trust::required(trust)->setResult(kSecTrustResultInvalid);
- Trust::required(trust)->exceptions(exceptions);
- }
- catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
- catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
- catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
- catch (...) { __secapiresult=errSecInternalComponent; }
-
- /* If there is a valid exception entry for our current leaf we're golden. */
- if (SecTrustGetExceptionForCertificateAtIndex(trust, 0))
- return true;
-
- /* The passed in exceptions didn't match our current leaf, so we discard it. */
- try {
- Trust::required(trust)->exceptions(NULL);
- __secapiresult = errSecSuccess;
- }
- catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
- catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); }
- catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; }
- catch (...) { __secapiresult=errSecInternalComponent; }
-
- return false;
-}
-#endif