iOS 8 has broken SSL connection in my app - CFNetwork SSLHandshake failed (-9806)

34,089

Solution 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.

Solution 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.

Share:
34,089
Darren
Author by

Darren

Updated on July 09, 2022

Comments

  • Darren
    Darren almost 2 years

    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

  • Darren
    Darren over 9 years
    Thanks. I don't quite know what's changed from iOS 7 to 8 to make it suddenly stop working. I've updated to AFNetworking v2 and get the authentication challenge call backs and basically tell it to ignore and carry on. This seems to work sometimes but not always. I'm wondering if I need to queue all the requests so only 1 goes at a time?
  • Darren
    Darren over 9 years
    Thanks. That's basically the same as what I have above. I think the code at the bottom of my question is actually working and the reason it sometimes doesn't is to do with this github.com/AFNetworking/AFNetworking/issues/…
  • Darren
    Darren over 9 years
    It seems that I do actually have the ssl side of things working. Although I get the SSLHandshake Failed messages, I successfully connect by bypassing the ssl as in my question. The reason why it only sometimes works I think is due to this github.com/AFNetworking/AFNetworking/issues/…