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))
}
}
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>
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.}
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.
- The first error I get is with the above code
- The second error I get is if I don't do the processing in the URLSessionDelegate
- The third error occurs if I establish a connection using the HTTP protocol and not HTTPS
Instead of using URLSessionDelegate to bypass the SSL validation, you can manually trust the certificate on the iOS device. Here's an example code: