iOS 8 has broken SSL connection in my app - CFNetw

2019-03-25 00:58发布

问题:

My app simply connects to a web server on a home device and reads some html. It works fine when using http, but now on iOS 8 when using https it does not work.

I use AFNetworking v1 and override the SSL checks using these override methods (Yes I know in normal circumstances this shouldn't be done and is unsafe etc.., but thats another topic).

[self setAuthenticationChallengeBlock:^(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge) {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        }
    }];

[self setAuthenticationAgainstProtectionSpaceBlock:^BOOL(NSURLConnection *connection, NSURLProtectionSpace *protectionSpace) {
        if([[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust]) {
                return YES; // Self-signed cert will be accepted
        }
        // If no other authentication is required, return NO for everything else
        // Otherwise maybe YES for NSURLAuthenticationMethodDefault and etc.
        return NO;
    }];

Now with iOS 8 I get an error like this:

CFNetwork SSLHandshake failed (-9806)

CFNetwork SSLHandshake failed (-9806)

CFNetwork SSLHandshake failed (-9806)

NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9806)

Error during connection: Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo=0x7b66c110 {NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorCodeKey=-9806, NSErrorFailingURLStringKey=https://xxx.xxx.xxx.xxx:443/live.htm, _kCFStreamErrorDomainKey=3, NSUnderlyingError=0x7c0d8a20 "An SSL error has occurred and a secure connection to the server cannot be made.", NSErrorFailingURLKey=https://xxx.xxx.xxx.xxx:443/Info.live.htm}

I have tried changing over to FSNetworking, and it sometimes works when setting this:

- (void)connection:(NSURLConnection *)connection
willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {

    if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        NSLog(@"Ignoring SSL");
        SecTrustRef trust = challenge.protectionSpace.serverTrust;
        NSURLCredential *cred;
        cred = [NSURLCredential credentialForTrust:trust];
        [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
        return;
    }
}

However doing 2 simultaneous request, only 1 will succeed and one will fail with a similar error to above. Only 1 request seems to reach the SSL override point.

Can anyone please shed some light on this and whats changed in iOS 8 to break this, and how I can possibly fix it?

Thanks

回答1:

I ran into the same kind of problem with iOS 8.

Scenario:

  1. Calls to our https server work
  2. Open a https URL from our server in a UIWebView
  3. All future NSURLConnections fail with a SSLHandshake error

useCredential:forAuthenticationChallenge was causing this error (but only after opening a page in https hosted on the same server) when we called SecTrust* methods right after.

This code triggered the error:

[challenge.sender useCredential:urlCredential forAuthenticationChallenge:challenge];
SecTrustRef trustRef = [[challenge protectionSpace] serverTrust];
CFIndex count = SecTrustGetCertificateCount(trustRef);

But this one did not:

SecTrustRef trustRef = [[challenge protectionSpace] serverTrust];
CFIndex count = SecTrustGetCertificateCount(trustRef);
[challenge.sender useCredential:urlCredential forAuthenticationChallenge:challenge];

It is not clear to me why this was causing the SSLHandshake to fail on iOS 8 but not iOS 7. Maybe AFNetworking does something after useCredential:forAuthenticationChallenge which is causing the same problem.



回答2:

The error you are seeing can be found in SecureTransport.h. It is a transport-level error: the connection failed because it was aborted.

A number of things could be the cause, on both the client and server. This is more likely to happen if the server is asking the client for a certificate and the client isn't providing one, at which point the server decides to give up. If the server is asking the client for a certificate, your delegate method should see an attempt to authenticate using a client certificate in addition to server trust.