4

I'm working at a simple client that needs to connect to a socket. This socket requires SSL...I'm trying to configure the client to support SSL but I'm getting this error:

CFNetwork SSLHandshake failed (-9807)

This is the code that I've written to configure the socket. Do you see anything strange/wrong? Also... the server is running on localhost and I'm running the iOS app on the simulator at the moment... may it be a problem?

class MySocket:NSObject {

    var inputStream: InputStream!
    var outputStream: OutputStream!

    func setupStream(){

        var readStream: Unmanaged<CFReadStream>?
        var writeStream: Unmanaged<CFWriteStream>?

        CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
                                           "127.0.0.1" as CFString,
                                           80,
                                           &readStream,
                                           &writeStream)

        inputStream = readStream!.takeRetainedValue()
        outputStream = writeStream!.takeRetainedValue()

        inputStream.delegate = self

        inputStream.schedule(in: .current, forMode: .common)
        outputStream.schedule(in: .current, forMode: .common)

    // SETTING SSL HERE
        inputStream.setProperty(kCFStreamSocketSecurityLevelNegotiatedSSL, forKey:  Stream.PropertyKey.socketSecurityLevelKey)
        outputStream.setProperty(kCFStreamSocketSecurityLevelNegotiatedSSL, forKey: Stream.PropertyKey.socketSecurityLevelKey)
    // END SSL SETUP

        inputStream.open()
        outputStream.open()

    }
}
MatterGoal
  • 16,038
  • 19
  • 109
  • 186
  • Are you sure your localhost server serves TCP over SSL on port 80 and not 443? – jms Nov 01 '19 at 01:28
  • @jms yes actually the port is a custom port.... I've written port 80 on this example, but we are using a custom port. – MatterGoal Nov 04 '19 at 13:02
  • Can you confirm that your server successfully servers secure content over ssl to other clients and this is only a swift issue so I can look more into it? (if you are worried about `127.0.0.1` then connect to another public network and use its interface ip-address from `ifconfig`) – jms Nov 05 '19 at 00:17
  • @jms yes I can confirm that it works on other clients (I have a very simple python script that can connect to the server and send and receive data). – MatterGoal Nov 05 '19 at 10:18
  • I think you are setting the SSL properties in the wrong places. Work with the `CFStream` API instead of the low level I/O Stream. The following link shows you how to set properties to a `CFStream` https://developer.apple.com/documentation/corefoundation/cfstream/stream_properties – jms Nov 07 '19 at 00:42
  • @jms what do you mean? I'm already using CFStream... – MatterGoal Nov 07 '19 at 20:13
  • Try it again on another network or refer this if works : https://stackoverflow.com/questions/38761837/ios-ssl-connection-in-swift – Dhaval Raval Nov 08 '19 at 15:04
  • @MatterGoal: how are you calling the clients that work vs calling this? – Najinsky Nov 10 '19 at 16:21
  • @Najinsky the client that works is a python client, it just easily sets SSL wrapping the socket with `ssl.wrap_socket(sock)` – MatterGoal Nov 11 '19 at 14:46
  • @DhavalRaval the case you are providing is different. That guy has to pin custom certificates... while I just need to enable SSL using the root certificates. – MatterGoal Nov 11 '19 at 14:48
  • @MatterGoal I think the answer provided by Saul will set you on the right path. This is what I meant when I said you were using the wrong API. Notice how he sets his stream properties as opposed to yours. That is the way apple has in its guides. – jms Nov 14 '19 at 04:42
  • Thank you @jms I'm not sure this is the solution. But I need to double check. I'll update this question as soon as possible. – MatterGoal Nov 14 '19 at 15:27

1 Answers1

1

I have been reviewing the library SocketRocket to check your code. The library is implemented in Objective-C but you can use it as a reference.

In that library, in the code to update the options for secure stream I have observed that it only updates the kCFStreamSocketSecurityLevelNegotiatedSSL for the outputStream.

- (void)_updateSecureStreamOptions {
    if (_secure) {
        NSMutableDictionary *SSLOptions = [[NSMutableDictionary alloc] init];

        /*ONLY FOR OUTPUT STREAM*/
        [_outputStream setProperty:(__bridge id)kCFStreamSocketSecurityLevelNegotiatedSSL forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel];

        // If we're using pinned certs, don't validate the certificate chain
        if ([_urlRequest SR_SSLPinnedCertificates].count) {
            [SSLOptions setValue:@NO forKey:(__bridge id)kCFStreamSSLValidatesCertificateChain];
        }

  #if DEBUG
        self.allowsUntrustedSSLCertificates = YES;
  #endif

        if (self.allowsUntrustedSSLCertificates) {
            [SSLOptions setValue:@NO forKey:(__bridge id)kCFStreamSSLValidatesCertificateChain];
            SRFastLog(@"Allowing connection to any root cert");
        }

        [_outputStream setProperty:SSLOptions
                            forKey:(__bridge id)kCFStreamPropertySSLSettings];
    }

    _inputStream.delegate = self;
    _outputStream.delegate = self;

    [self setupNetworkServiceType:_urlRequest.networkServiceType];
}

I hope that it helps.

93sauu
  • 3,770
  • 3
  • 27
  • 43