Posts

Post marked as solved
9 Replies
0 Views
I finally found a solution to the OCSP requests not being sent. The problem was caused by the /etc/hosts file. I have my server and my OCSP responder hosted on the same machine. That is why I had a line in the hosts file like: 192.168.x.x server1.local.com server2.local.com ocsp.responder.com These are just placeholder names. With this line I could not see any OCSP requests on my WireShark trace. As soon as I decoupled those lines in the /etc/hosts file like: 192.168.x.x server1.local.com server2.local.com ocsp.responder.com 192.168.x.x ocsp.responder.com I could see OCSP requests from the macOS machine to my OCSP responder. Everything now works pretty well. This macOS machines was running Monterey(12.4) , but I do compile my project with the target OS being 10.15.
Post marked as solved
9 Replies
0 Views
The server is not responding with an OCSP check in the handshake negotiation. OCSP stapling is not enabled on the server. I tried two leaf certificate with my new root CA and still no OCSP messages on the WireShark traces. Weirdly when I try to visit websites hosted by digicert.com which server revoked certificates from their CAs, I can see the OCSP messages going to http://ocsp.digicert.com. The application correctly recognizes the revoked certificate and fails the TLS trust evaluation. These test websites can be found here: DigiCert Root Certificates - Download & Test | DigiCert.com
Post marked as solved
9 Replies
0 Views
I have submitted another feedback report (FB10033659) for your reference. I can download the CRL and access OCSP endpoint from my macOS machine. I also verified the server certificate revocation status using an OpenSSL command: openssl ocsp -issuer caCert.cer -cert switchCert.cer -text -url http://<address>/ocsp I am able to get the response back like this for a revoked certificate: Response Verify Failure 4571629228:error:27FFF065:OCSP routines:CRYPTO_internal:certificate verify error:/AppleInternal/Library/BuildRoots/b6051351-c030-11ec-96e9-3e7866fcf3a1/Library/Caches/com.apple.xbs/Sources/libressl/libressl-2.8/crypto/ocsp/ocsp_vfy.c:141:Verify error:unable to get local issuer certificate switchCert.cer: revoked This Update: May 31 16:14:42 2022 GMT Next Update: Jun 2 04:34:42 2022 GMT Reason: certificateHold Revocation Time: May 31 16:24:00 2022 GMT This is all expected, but my macOS Command Line test app as you suggested I make still makes no requests to the OCSP endpoint where I am running WireShark traces to monitor incoming traffic. This is both with a valid or invalid chain. To expand that a bit more, the chain the server sends to the macOS machine is the leaf certificate and the root CA. This root CA I have added to the keychain and marked as "Always Trust" for everything in Keychain Access. Weirdly both Chrome and Safari mark this revoked server certificate as valid, when I try to make a HTTPS request to the server. Also not making any requests to the CRL or OCSP endpoints. On my Windows machines, this certificate is marked correctly as revoked in chrome when I try to make HTTPS requests to the same server. Is this something related?
Post marked as solved
9 Replies
0 Views
Thanks meaton. I did not come across any documentation saying CRL checks had been removed from 10.15. I set up an OCSP responder setup using a Windows server and I can see OCSP requests coming in for my Windows clients but the macOS client does not send any such request. Still getting the error code -67635 corresponding to errSecIncompleteCertRevocationCheck. I prefer to make this whole operation synchronously, so was continuing to use SecTrustEvaluateWithError but when that continued to give me the same errors, I switched over to SecTrustEvaluateAsyncWithError. I was blocking the main thread using a std::promise and std::future setup like this: std::future<void> barrier_future = m_barrier.get_future(); std::thread workThread(TrustEval); barrier_future.wait(); workThread.join(); if(trustEvalResult) { fprintf(stderr,"COMPLETE = TRUE \n"); complete(true); } else { fprintf(stderr,"COMPLETE = FALSE \n"); complete(false); } where m_barrier and trustEvalResult are global variables. This code is still inside the sec_protocol_options_set_verify_block. The TrustEval function running in a separate thread namely workThread is: void TrustEval() { fprintf(stderr,"Starting TRUST EVAL \n"); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ SecTrustEvaluateAsyncWithError(peerTrust, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(SecTrustRef evaluatedTrust, bool trustResult, CFErrorRef error) { if (trustResult) { fprintf(stderr,"TRUST EVAL SUCCESSFUL \n"); // Evaluation succeeded! trustEvalResult = true; } else { fprintf(stderr,"TRUST EVAL FAILED \n"); // Evaluation failed: Check the error trustEvalResult = false; } // Finally, release the trust and error. if (evaluatedTrust) { CFRelease(evaluatedTrust); } if (error) { CFRelease(error); } fprintf(stderr,"Setting m_barrier \n"); m_barrier.set_value(); } ); }); } But still see the revocation check fail from the SecTrustWithErrorCallback block. And no OCSP requests from the macOS machine. I should mention going to the browser I can access the crl and ocsp endpoint urls.
Post marked as solved
9 Replies
0 Views
Posting the code snippet above here as well as I reached word limit above: sec_protocol_options_set_verify_block(sec_options, ^(sec_protocol_metadata_t metadata, sec_trust_t trust_ref, sec_protocol_verify_complete_t complete){ if (ignoreCertValidation) { logger->Info("TLS certificate validation errors will be ignored."); complete(true); } else { SecTrustRef peerTrust = NULL; if (!(peerTrust = sec_trust_copy_ref(trust_ref))) { logger->Error("Unable to copy SecTrustRef for SSL verification."); } CFArrayRef trustPolicy = NULL; SecPolicyRef revocationPolicy = NULL; OSStatus copyPolicyStatus = SecTrustCopyPolicies(peerTrust, &trustPolicy); if (copyPolicyStatus != errSecSuccess) { string errMessage = StringUtils::CFStringRefToString(SecCopyErrorMessageString(copyPolicyStatus, NULL)); logger->Error("Unable to create additional policies for TLS trust evaluation. Reason: %s", errMessage.c_str()); } else { CFMutableArrayRef mPolicies = CFArrayCreateMutableCopy(kCFAllocatorDefault, (CFArrayGetCount(trustPolicy) + 1), trustPolicy); CFRelease(trustPolicy); SecPolicyRef sslPolicy = (SecPolicyRef)CFArrayGetValueAtIndex(mPolicies, 0); CFDictionaryRef sslPolicyProperties = SecPolicyCopyProperties(sslPolicy); CFStringRef policyType = (CFStringRef)CFDictionaryGetValue(sslPolicyProperties, kSecPolicyOid); if (policyType && CFEqual(kSecPolicyAppleSSL, policyType)) // Only apply revocation to SSL validation { if (crlChecks == CRLChecks::Hard) { revocationPolicy = SecPolicyCreateRevocation(kSecRevocationCRLMethod | kSecRevocationRequirePositiveResponse); } else { revocationPolicy = SecPolicyCreateRevocation(kSecRevocationCRLMethod); } if (revocationPolicy) { CFArrayAppendValue(mPolicies, revocationPolicy); OSStatus setPolicyStatus = SecTrustSetPolicies(peerTrust, mPolicies); if (setPolicyStatus != errSecSuccess) { string errMessage = StringUtils::CFStringRefToString(SecCopyErrorMessageString(setPolicyStatus, NULL)); logger->Error("Unable to add additional policies for TLS evaluation. Reason: %s", errMessage.c_str()); } } } if (revocationPolicy) { CFRelease(revocationPolicy); } if (sslPolicyProperties) { CFRelease(sslPolicyProperties); } if (mPolicies) { CFRelease(mPolicies); } } CFErrorRef trustError = NULL; if (SecTrustEvaluateWithError(peerTrust, &trustError)) { logger->Debug("TLS trust evaluation successful"); complete(true); } else { SecTrustResultType trustResult; SecTrustGetTrustResult(peerTrust, &trustResult); switch(trustResult) { case kSecTrustResultUnspecified: logger->Error("Trust evaluation result - kSecTrustResultUnspecified"); break; case kSecTrustResultProceed: logger->Error("Trust evaluation result - kSecTrustResultProceed"); break; case kSecTrustResultDeny: logger->Error("Trust evaluation result - kSecTrustResultDeny"); break; case kSecTrustResultRecoverableTrustFailure: logger->Error("Trust evaluation result - kSecTrustResultRecoverableTrustFailure"); break; case kSecTrustResultFatalTrustFailure: logger->Error("Trust evaluation result - kSecTrustResultFatalTrustFailure"); break; case kSecTrustResultOtherError: logger->Error("Trust evaluation result - kSecTrustResultOtherError"); break; case kSecTrustResultInvalid: logger->Error("Trust evaluation result - kSecTrustResultInvalid"); break; } CFDictionaryRef trust_results = NULL; trust_results = SecTrustCopyResult(peerTrust); CFBooleanRef revoChecked = (CFBooleanRef)CFDictionaryGetValue(trust_results, kSecTrustRevocationChecked); if(revoChecked == kCFBooleanTrue) { logger->Error("Revocation check returned TRUE"); } else { logger->Error("Revocation check returned FALSE"); } if(trust_results) { CFRelease(trust_results); } // Call to CFErrorCopyDescription can sometimes return the wrong error message strings. // Check the Security.framework error codes at Security.framework/Headers/SecBase.h CFIndex errCode = CFErrorGetCode(trustError); const string errMessage = StringUtils::CFStringRefToString(CFErrorCopyDescription(trustError)); logger->Error("TLS trust evaluation failed. Error: %ld '%s'", errCode, errMessage.c_str()); complete(false); } if (trustError) { CFRelease(trustError); } if (peerTrust) { CFRelease(peerTrust); } } }, m_connectionQueue);