如何正确转换startTLS和XMPPFramework

时间:2017-09-28 21:18:03

标签: ios swift x509 xmppframework starttls

我手上有一个令人困惑的挑战,客户端提供base64格式的私有/公共TLS证书(没有典型的PEM页眉/页脚)和x509证书(正确的PEM编码)。以下是从客户端收到的密钥

公钥(测试服务器,这里没有安全问题!):

MIGbMBQGByqGSM49AgEGCSskAwMCCAEBDQOBggAEo6friRZd+TRPoubQKlaSNPC6cr0WFkrPy8jiOdBH5SZ07OtvaefkOpxu1Z/D00xaRvLrqNGllhiTW6k7bnN14Z2M+90lF0zXMwCzj8BrJTqNETSx1yt1LMHRmWZc8bEU6aixxDB2se08WUSISlVX7cNdq5DJIBhl04/Gts/Mj8s=

私钥:

MIH5AgEAMBQGByqGSM49AgEGCSskAwMCCAEBDQSB3TCB2gIBAQRAqdkO5SD0uCf7zAckNyYXlP74mwRkyO4Jorv9kSjtrWQ2zAZnuK01rX2V68q+6bnOH4fY4ZqXm31KUIdqBYD/9KALBgkrJAMDAggBAQ2hgYUDgYIABKOn64kWXfk0T6Lm0CpWkjTwunK9FhZKz8vI4jnQR+UmdOzrb2nn5DqcbtWfw9NMWkby66jRpZYYk1upO25zdeGdjPvdJRdM1zMAs4/AayU6jRE0sdcrdSzB0ZlmXPGxFOmoscQwdrHtPFlEiEpVV+3DXauQySAYZdOPxrbPzI/L

和x509:

-----BEGIN CERTIFICATE-----
MIIDzDCCArSgAwIBAgIQEMGgPQmVXkgj00ObG/QomDANBgkqhkiG9w0BAQsFADBB
<!snipped!> contains the IP address :P
Q7wO4S7yQe/I4grciNr72Q==
-----END CERTIFICATE-----

已收到的x509证书可以在Keychain Assistant中导入,因此我确信格式正确。这是我用来将3个证书提取为字符串,将它们转换为数据并将它们转发到XMPPFramework的代码:

import UIKit
import XMPPFramework
import CryptoSwift

class XmppController: NSObject, XMPPStreamDelegate, XMPPRosterDelegate {

    static let shared = XmppController()

    let connectionTimeout: TimeInterval = TimeInterval(90)
    let heartbeat: TimeInterval = TimeInterval(300)

    let stream = XMPPStream()
    let reconnect = XMPPReconnect()
    let dispatchQueue = DispatchQueue(label: "xmpp",
                                      qos: DispatchQoS.background,
                                      attributes: [DispatchQueue.Attributes.concurrent],
                                      autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit,
                                      target: nil)

    override init() {
        super.init()
        configureLibrary()
    }

    func isOnline() -> Bool {
        return stream?.isConnected() ?? false
    }

    func goOffline() {
        dispatchQueue.async {
            self.reconnect?.deactivate()
            if self.stream?.isConnected() ?? false {
                let presence = XMPPPresence(type: "unavailable")
                self.stream?.send(presence)
            }
            self.stream?.disconnect()
        }
    }

    func goOnline() {
        dispatchQueue.async {
            if self.stream?.isDisconnected() ?? false {
                self.reconnect?.activate(self.stream)
                do {
                    print("XMPP attempting to connect to \(self.stream!.hostName!) at port \(self.stream!.hostPort)")
                    try self.stream?.connect(withTimeout: self.connectionTimeout)
                    print("XMPP connection established")

                    let presence = XMPPPresence()
                    self.stream?.send(presence)
                } catch {
                    print("XMPP connection failed")
                }
            }
        }
    }

    func configureLibrary() {
        let profile = UserProfile.shared
        guard profile.xmppDomain != nil && profile.xmppUserName != nil && profile.xmppHostName != nil else {
            return
        }

        stream?.hostName = profile.xmppHostName!
        stream?.hostPort = UInt16(profile.xmppPort ?? 0)
        stream?.myJID = XMPPJID(user: profile.xmppUserName!, domain: profile.xmppDomain!, resource: nil)
        stream?.addDelegate(self, delegateQueue: dispatchQueue)
        stream?.startTLSPolicy = .preferred
        stream?.keepAliveInterval = heartbeat
    }

    func xmppStreamWillConnect(_ sender: XMPPStream!) {
        print("xmppStreamWillConnect")
    }

    func xmppStreamDidConnect(_ sender: XMPPStream!) {
        print("xmppStreamDidConnect")
    }

    func xmppStreamConnectDidTimeout(_ sender: XMPPStream!) {
        print("xmppStreamConnectDidTimeout")
    }

    func xmppStreamDidDisconnect(_ sender: XMPPStream!, withError error: Error!) {
        print("xmppStreamDidDisconnect, error: \(error)")
    }

    func xmppStreamDidSecure(_ sender: XMPPStream!) {
        print("xmppStreamDidSecure")
    }

    func xmppStreamDidRegister(_ sender: XMPPStream!) {
        print("xmppStreamDidRegister")
    }

    func xmppStreamDidAuthenticate(_ sender: XMPPStream!) {
        print("xmppStreamDidAuthenticate")
    }

    func xmppStream(_ sender: XMPPStream!, willSecureWithSettings settings: NSMutableDictionary!) {
        print("xmppStream:willSecureWithSettings")
        let profile = UserProfile.shared
        if profile.xmppPrivateKey != nil && profile.xmppPublicKey != nil {
            let privateKey = Data(base64Encoded: profile.xmppPrivateKey)
            let publicKey = Data(base64Encoded: profile.xmppPublicKey)
            let x509cert = unpackX509(profile.xmppServerX509Certificate!)
            let certificates = NSArray(array: [publicKey!, privateKey!, x509cert])
            let certificatesKey = NSString(string: kCFStreamSSLCertificates)
            let securityLevelKey = NSString(string: kCFStreamSSLLevel)
            let peerNameKey = NSString(string: kCFStreamSSLPeerName)
            settings.setObject(certificates, forKey: certificatesKey)
            settings.setObject(StreamSocketSecurityLevel.negotiatedSSL, forKey: securityLevelKey)
            settings.setObject(profile.xmppHostName!, forKey: peerNameKey)
        }
    }

    func unpackX509(_ x509: String) -> Data {
        if x509.hasPrefix("-----BEGIN CERTIFICATE-----\n") && x509.hasSuffix("-----END CERTIFICATE-----\n") {
            var parts = x509.components(separatedBy: "\n")
            parts.removeFirst()
            parts.removeLast()
            parts.removeLast()
            let x509Base64 = parts.joined()
            let x509Data = Data(base64Encoded: x509Base64)
            return x509Data ?? Data()
        }
        return Data()
    }
}

以下是代码运行时的相关日志输出:

XMPP attempting to connect to <!snipped!> at port 5222
XMPP connection established
xmppStreamWillConnect
...
xmppStream:willSecureWithSettings
xmppStreamDidDisconnect, error: Optional(Error Domain=GCDAsyncSocketErrorDomain Code=8 "Error in SSLSetCertificate" UserInfo={NSLocalizedDescription=Error in SSLSetCertificate})

如果有人能够在xmppStream期间如何正确地准备数组以传递给XMPPFramework:willSecureWithSettings将非常感激。目前,SSLCertificates被拒绝了。

注意:由于服务器配置,我无法打包预先生成的P12文件;我必须使用的数据采用上面突出显示的格式。

谢谢!

0 个答案:

没有答案