We have certificate pinning for our app used by millions of customers, and we recently moved from using an Amazon CA to our company custom CA certificate. We followed the following these steps:
- Include a copy of the certificate authority's root certificate in the app
- Once you have the trust object, create a certificate object from the certificate data (SecCertificateCreateWithData) and then set that certificate as a trusted anchor for the trust object (SecTrustSetAnchorCertificates)
- SecTrustSetAnchorCertificates sets a flag that prevents the trust object from trusting any other anchors, if you also want to trust the default system anchors, call SecTrustSetAnchorCertificatesOnly to clear that flag
- Evaluate the trust object as per usual
SecTrustEvaluate returns .unspecified and we call completionHandler(.useCredential, credential) on the completion handler for urlSession:didReceive:completionHandler.
However, the error we get is:
Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSErrorPeerCertificateChainKey=(
"<cert(0x12e0e8800) s: mydomain.com i: mydomain.com>"
), NSErrorClientCertificateStateKey=0, NSErrorFailingURLKey=https://mydomain.com/xxxxx, NSErrorFailingURLStringKey=https://mydomain.com/xxxxx, NSUnderlyingError=0x283885110 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x2804e15f0>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=(
"<cert(0x12e0e8800) s: mydomain.com/xcom i: mydomain.com>"
)}}, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <56BD63E5-3D28-4EBF-83DC-C11C744DF4E4>.<1>"
), _kCFStreamErrorCodeKey=-9802, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <56BD63E5-3D28-4EBF-83DC-C11C744DF4E4>.<1>, NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x2804e15f0>, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made.}
The only solution so far was to install the certificate on the simulator then it worked. However, we are not in a position to get customers to install the certificate - whether via MDM or otherwise. Is there a seamless solution for using custom certificates as I don't think Apple recommends (or even allows nowadays) to add exception domains in the plist?