0

My task is to create a remote control for Android TV for iOS. After unsuccessful attempts to find any SDK that provides such an opportunity, I decided to rewrite androidtv-remote. This library can do everything I need. To create a TLS connection, I decided to use the SocketIO. But my problem is that the TV has an untrusted certificate and the connection cannot happen.

let manager = SocketManager(
    socketURL: .init(string: "https://\(host):\(port)")!,
    config: [
        .sessionDelegate(self)
    ]
)

self.socketManager = manager
let socket = manager.defaultSocket

socket.onAny { event in
    print(event.event.uppercased())
}

socket.connect()


extension PairingManager: URLSessionDelegate {
    func urlSession(
        _ session: URLSession,
        didReceive challenge: URLAuthenticationChallenge,
        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?
        ) -> Void) {
        guard let serverTrust = challenge.protectionSpace.serverTrust else {
            completionHandler(.performDefaultHandling, nil)

            return
        }

        completionHandler(.useCredential, .init(trust: serverTrust))
    }
}
  1. Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSErrorFailingURLStringKey=https://192.168.0.101:6467/socket.io/?transport=polling&b64=1&EIO=4, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <324E645E-2EB5-4024-A361-AAC93D7895C2>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=( "LocalDataTask <324E645E-2EB5-4024-A361-AAC93D7895C2>.<1>

  2. Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “192.168.0.101” which could put your confidential information at risk." UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSErrorPeerCertificateChainKey=( "<cert(0x10500e400) s: atvremote/MTCMSD6886EU/bangbae/EU 4K Android TV/1C:30:08:93:4C:CD i: atvremote/MTCMSD6886EU/bangbae/EU 4K Android TV/1C:30:08:93:4C:CD>" ), NSErrorClientCertificateStateKey=0, NSErrorFailingURLKey=https://192.168.0.101:6467/socket.io/?transport=polling&b64=1&EIO=4, NSErrorFailingURLStringKey=https://192.168.0.101:6467/socket.io/?transport=polling&b64=1&EIO=4, NSUnderlyingError=0x2827bd110 {Error Domain=kCFErrorDomainCFNetwork Code=-1202 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x2818ec0a0>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9807, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9807, kCFStreamPropertySSLPeerCertificates=( "<cert(0x10500e400) s: atvremote/MTCMSD6886EU/bangbae/EU 4K Android TV/1C:30:08:93:4C:CD i: atvremote/MTCMSD6886EU/bangbae/EU 4K Android TV/1C:30:08:93:4C:CD>" )}}, _NSURLErrorRelatedURLSessionTaskErrorKey=( "LocalDataTask <5CC821A4-3477-4201-8CBE-0E2BA018DF02>.<1>" ), _kCFStreamErrorCodeKey=-9807, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <5CC821A4-3477-4201-8CBE-0E2BA018DF02>.<1>, NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x2818ec0a0>, NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “192.168.0.101” which could put your confidential information at risk.}

  3. Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost." UserInfo={_kCFStreamErrorCodeKey=-4, NSUnderlyingError=0x2803512c0 {Error Domain=kCFErrorDomainCFNetwork Code=-1005 "(null)" UserInfo={NSErrorPeerAddressKey=<CFData 0x282e15f40 [0x2208eac08]>{length = 16, capacity = 16, bytes = 0x10021943c0a800650000000000000000}, _kCFStreamErrorCodeKey=-4, _kCFStreamErrorDomainKey=4}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <49F62856-E6A2-4F2A-9A0F-B4FDA7473E3F>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=( "LocalDataTask <49F62856-E6A2-4F2A-9A0F-B4FDA7473E3F>.<1>" ), NSLocalizedDescription=The network connection was lost., NSErrorFailingURLStringKey=http://192.168.0.101:6467/socket.io/?transport=polling&b64=1&EIO=4, NSErrorFailingURLKey=http://192.168.0.101:6467/socket.io/?transport=polling&b64=1&EIO=4, _kCFStreamErrorDomainKey=4}

But as a result, I get different errors, depending on the configuration.

  1. The first error I get is with the above code
  2. The second error I get is if I don't do the processing in the URLSessionDelegate
  3. The third error occurs if I establish a connection using the HTTP protocol and not HTTPS
  • 1
    you can not achieve this using SocketIO, you need to establish TLS connection using `NWConnection` of `Network` framework. – Samir Bagaria May 30 '23 at 12:36

2 Answers2

0

Instead of using URLSessionDelegate to bypass the SSL validation, you can manually trust the certificate on the iOS device. Here's an example code:

func trustCertificateManually() {
let host = "host"
let port = "port"

guard let serverURL = URL(string: "https://\(host):\(port)") else {
    return
}

let serverTrust = serverURL.securityTrust()

if serverTrust != nil {
    // Save the serverTrust object for the duration of your app's session
    URLCredentialStorage.shared.setCredential(
        URLCredential(trust: serverTrust!),
        for: serverURL
    )
}

// Proceed with establishing the connection
let manager = SocketManager(socketURL: serverURL)
// your code...
   }

    extension URL {
    func securityTrust() -> SecTrust? {
     var trust: SecTrust?
     let policy = SecPolicyCreateSSL(true, self.host as CFString)
     let status = SecTrustCreateWithCertificates(self as CFURL, policy, &trust)
    
    guard status == errSecSuccess else {
        return nil
    }
    
    return trust
}
}
0

You should use the Network framework is have wrote Samir. NWConnection + NWParameters with NWProtocolTLS.Options

Zetsu
  • 17
  • 2