iossslsecure-transport

Overriding TLS server validation hostname doesn't seem to be working


I'm trying to connect my app to a development server that has a server certificate with the wrong hostname, but it is signed by a trusted anchor certificate. When I evaluate the server trust object, it fails as expected. I am trying to change the trust evaluation policy for the server's hostname, but it doesn't seem to help.

// In -connection:willSendRequestForAuthenticationChallenge:
// NSURLAuthenticationMethodServerTrust
SecTrustRef trust = [challenge.protectionSpace serverTrust];
SecTrustResultType trustResult;
SecTrustEvaluate(trust, &trustResult);
// trustResult == kSecTrustResultRecoverableTrustFailure

SecPolicyRef policyOverride = SecPolicyCreateSSL(true, (CFStringRef)@"devhost");
CFArrayRef policies = (CFArrayRef)@[policyOverride];
SecTrustSetPolicies(trust, policies);
CFRelease(policyOverride);
SecTrustEvaluate(trust, &trustResult);
// trustResult == kSecTrustResultRecoverableTrustFailure

As far as I understand, the second time I call SecTrustEvaluate(), it should be returning kSecTrustResultUnspecified. I have connected to the dev server using "devhost" when I initialized the NSURLConnection, and challenge.protectionSpace.host == @"devhost" as well. What am I doing wrong here?


Solution

  • I was using the wrong host name in the call to SecPolicyCreateSSL.

    When using SecPolicyCreateSSL to override hostname validation, the hostname argument should be one that matches the certificate you're validating. Then the validation pretends that the host you're communicating with has the newly specified hostname.

    In my case, the server has a certificate for "*.mydomain.tld", so I call

    SecPolicyCreateSSL(true, (CFStringRef)@"devhost.mydomain.tld");
    

    and then the certificate chain can be successfully validated.