From 2df529b0c748dca7883fb3afa01df45d544b7fb7 Mon Sep 17 00:00:00 2001 From: leeway Date: Sat, 4 Mar 2023 23:19:47 +0800 Subject: [PATCH] feat: add self signed delegate and demo --- Example/Example/ViewController.swift | 34 ++++++++++++++++------------ Source/CocoaMQTT.swift | 10 +++++++- Source/CocoaMQTT5.swift | 8 +++++++ Source/CocoaMQTTSocket.swift | 1 + Source/CocoaMQTTWebSocket.swift | 21 +++++++++++++---- 5 files changed, 55 insertions(+), 19 deletions(-) diff --git a/Example/Example/ViewController.swift b/Example/Example/ViewController.swift index 2fbfa76d..066f4601 100644 --- a/Example/Example/ViewController.swift +++ b/Example/Example/ViewController.swift @@ -458,25 +458,31 @@ extension ViewController: CocoaMQTT5Delegate { } } - +let myCert = "myCert" extension ViewController: CocoaMQTTDelegate { - // Optional ssl CocoaMQTTDelegate - func mqtt(_ mqtt: CocoaMQTT, didReceive trust: SecTrust, completionHandler: @escaping (Bool) -> Void) { - TRACE("trust: \(trust)") - /// Validate the server certificate - /// - /// Some custom validation... - /// - /// if validatePassed { - /// completionHandler(true) - /// } else { - /// completionHandler(false) - /// } - completionHandler(true) + // self signed delegate + func mqttUrlSession(_ mqtt: CocoaMQTT, didReceiveTrust trust: SecTrust, didReceiveChallenge challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void){ + if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) { + + let certData = Data(base64Encoded: myCert as String)! + + if let trust = challenge.protectionSpace.serverTrust, + let cert = SecCertificateCreateWithData(nil, certData as CFData) { + let certs = [cert] + SecTrustSetAnchorCertificates(trust, certs as CFArray) + + completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: trust)) + return + } + } + + completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil) + } + func mqtt(_ mqtt: CocoaMQTT, didConnectAck ack: CocoaMQTTConnAck) { TRACE("ack: \(ack)") diff --git a/Source/CocoaMQTT.swift b/Source/CocoaMQTT.swift index 566e917d..1dc57177 100644 --- a/Source/CocoaMQTT.swift +++ b/Source/CocoaMQTT.swift @@ -77,7 +77,9 @@ import MqttCocoaAsyncSocket /// /// This method will be called if enable `allowUntrustCACertificate` @objc optional func mqtt(_ mqtt: CocoaMQTT, didReceive trust: SecTrust, completionHandler: @escaping (Bool) -> Void) - + + @objc optional func mqttUrlSession(_ mqtt: CocoaMQTT, didReceiveTrust trust: SecTrust, didReceiveChallenge challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) + /// @objc optional func mqtt(_ mqtt: CocoaMQTT, didPublishComplete id: UInt16) @@ -571,6 +573,12 @@ extension CocoaMQTT: CocoaMQTTSocketDelegate { didReceiveTrust(self, trust, completionHandler) } + public func socketUrlSession(_ socket: CocoaMQTTSocketProtocol, didReceiveTrust trust: SecTrust, didReceiveChallenge challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { + printDebug("Call the SSL/TLS manually validating function - socketUrlSession") + + delegate?.mqttUrlSession?(self, didReceiveTrust: trust, didReceiveChallenge: challenge, completionHandler: completionHandler) + } + // ? public func socketDidSecure(_ sock: MGCDAsyncSocket) { printDebug("Socket has successfully completed SSL/TLS negotiation") diff --git a/Source/CocoaMQTT5.swift b/Source/CocoaMQTT5.swift index 36a6f875..7ee063d9 100644 --- a/Source/CocoaMQTT5.swift +++ b/Source/CocoaMQTT5.swift @@ -71,6 +71,8 @@ import MqttCocoaAsyncSocket /// This method will be called if enable `allowUntrustCACertificate` @objc optional func mqtt5(_ mqtt5: CocoaMQTT5, didReceive trust: SecTrust, completionHandler: @escaping (Bool) -> Void) + @objc optional func mqtt5UrlSession(_ mqtt: CocoaMQTT5, didReceiveTrust trust: SecTrust, didReceiveChallenge challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) + /// @objc optional func mqtt5(_ mqtt5: CocoaMQTT5, didPublishComplete id: UInt16, pubCompData: MqttDecodePubComp?) @@ -613,6 +615,12 @@ extension CocoaMQTT5: CocoaMQTTSocketDelegate { didReceiveTrust(self, trust, completionHandler) } + public func socketUrlSession(_ socket: CocoaMQTTSocketProtocol, didReceiveTrust trust: SecTrust, didReceiveChallenge challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { + printDebug("Call the SSL/TLS manually validating function - socketUrlSession") + + delegate?.mqtt5UrlSession?(self, didReceiveTrust: trust, didReceiveChallenge: challenge, completionHandler: completionHandler) + } + // ? public func socketDidSecure(_ sock: MGCDAsyncSocket) { printDebug("Socket has successfully completed SSL/TLS negotiation") diff --git a/Source/CocoaMQTTSocket.swift b/Source/CocoaMQTTSocket.swift index b393d183..9dbf9142 100644 --- a/Source/CocoaMQTTSocket.swift +++ b/Source/CocoaMQTTSocket.swift @@ -13,6 +13,7 @@ import MqttCocoaAsyncSocket public protocol CocoaMQTTSocketDelegate: AnyObject { func socketConnected(_ socket: CocoaMQTTSocketProtocol) func socket(_ socket: CocoaMQTTSocketProtocol, didReceive trust: SecTrust, completionHandler: @escaping (Bool) -> Swift.Void) + func socketUrlSession(_ socket: CocoaMQTTSocketProtocol, didReceiveTrust trust: SecTrust, didReceiveChallenge challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) func socket(_ socket: CocoaMQTTSocketProtocol, didWriteDataWithTag tag: Int) func socket(_ socket: CocoaMQTTSocketProtocol, didRead data: Data, withTag tag: Int) func socketDidDisconnect(_ socket: CocoaMQTTSocketProtocol, withError err: Error?) diff --git a/Source/CocoaMQTTWebSocket.swift b/Source/CocoaMQTTWebSocket.swift index c6ced69a..6f2e480e 100644 --- a/Source/CocoaMQTTWebSocket.swift +++ b/Source/CocoaMQTTWebSocket.swift @@ -14,8 +14,10 @@ import CocoaMQTT // MARK: - Interfaces public protocol CocoaMQTTWebSocketConnectionDelegate: AnyObject { - + func connection(_ conn: CocoaMQTTWebSocketConnection, didReceive trust: SecTrust, completionHandler: @escaping (Bool) -> Swift.Void) + + func urlSessionConnection(_ conn: CocoaMQTTWebSocketConnection, didReceiveTrust trust: SecTrust, didReceiveChallenge challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) func connectionOpened(_ conn: CocoaMQTTWebSocketConnection) @@ -149,7 +151,7 @@ public class CocoaMQTTWebSocket: CocoaMQTTSocketProtocol { internal var delegate: CocoaMQTTSocketDelegate? internal var delegateQueue: DispatchQueue? internal var internalQueue = DispatchQueue(label: "CocoaMQTTWebSocket") - + private var connection: CocoaMQTTWebSocketConnection? private func reset() { @@ -256,8 +258,17 @@ public class CocoaMQTTWebSocket: CocoaMQTTSocketProtocol { } extension CocoaMQTTWebSocket: CocoaMQTTWebSocketConnectionDelegate { - public func connection(_ conn: CocoaMQTTWebSocketConnection, didReceive trust: SecTrust, completionHandler: @escaping (Bool) -> Swift.Void) { - guard conn.isEqual(connection) else { return } + public func urlSessionConnection(_ conn: CocoaMQTTWebSocketConnection, didReceiveTrust trust: SecTrust, didReceiveChallenge challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { + if let del = delegate { + __delegate_queue { + del.socketUrlSession(self, didReceiveTrust: trust, didReceiveChallenge: challenge, completionHandler: completionHandler) + } + } else { + completionHandler(.performDefaultHandling, nil) + } + } + + public func connection(_ conn: CocoaMQTTWebSocketConnection, didReceive trust: SecTrust, completionHandler: @escaping (Bool) -> Void) { if let del = delegate { __delegate_queue { del.socket(self, didReceive: trust, completionHandler: completionHandler) @@ -366,6 +377,8 @@ extension CocoaMQTTWebSocket.FoundationConnection: URLSessionWebSocketDelegate { delegate.connection(self, didReceive: trust) { shouldTrust in completionHandler(shouldTrust ? .performDefaultHandling : .rejectProtectionSpace, nil) } + delegate.urlSessionConnection(self, didReceiveTrust: trust, didReceiveChallenge: challenge, completionHandler: completionHandler) + } else { completionHandler(.performDefaultHandling, nil) }