我手上有一个令人困惑的挑战,客户端提供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文件;我必须使用的数据采用上面突出显示的格式。
谢谢!