套接字自签名证书握手失败

时间:2017-07-07 10:11:17

标签: swift xcode sockets starscream

我正在使用Starscream套接字库,我正在尝试使用WSS但是我握手失败了。我拿到了自签名证书,我将其转换为.der文件。这是我正在尝试的代码

 var socket = WebSocket(url: URL(string: "wss://192.168.1.130:6223")!, protocols: [])

    override func viewDidLoad() {
        super.viewDidLoad()
        do
        {
            let urlPath     = Bundle.main.path(forResource: "my_cert", ofType: "der")
            let url         = NSURL.fileURL(withPath: urlPath!)
            let certificateData = try Data(contentsOf: url)

            let certificate: SecCertificate =
                SecCertificateCreateWithData(kCFAllocatorDefault, certificateData as CFData)!

            var trust: SecTrust?
            let policy = SecPolicyCreateBasicX509()
            let status = SecTrustCreateWithCertificates(certificate, policy, &trust)
            if status == errSecSuccess {
                let key = SecTrustCopyPublicKey(trust!)!;
                let ssl =  SSLCert(key: key)
                socket.security = SSLSecurity(certs: [ssl], usePublicKeys: true)
                socket.delegate = self
                socket.connect()
            }

        }catch let error as NSError
        {
            print(error)
        }
    }

因此,当我尝试连接时,收到以下错误消息

  

2017-07-07 11:06:26.590 CertificateTesting [5180:81661] CFNetwork   SSLHandshake失败(-9807)websocket断开连接:操作   无法完成。 (OSStatus错误-9807。)

证书应该可以正常工作,我的Android同事已经尝试过并且没有任何问题。我可以让它在我身边工作的唯一方法是如果我禁用SSL验证

 socket.disableSSLCertValidation = true

有没有人有使用套接字的自签名SSL的经验。任何信息都将非常感激。

编辑:

我调用了verify ssl命令,它返回

➜  CertificateTesting git:(master) ✗ openssl verify -my_cert.der ca-cert.pem server-cert.pem
usage: verify [-verbose] [-CApath path] [-CAfile file] [-purpose purpose] [-crl_check] [-engine e] cert1 cert2 ...
recognized usages:
    sslclient   SSL client
    sslserver   SSL server
    nssslserver Netscape SSL server
    smimesign   S/MIME signing
    smimeencrypt    S/MIME encryption
    crlsign     CRL signing
    any         Any Purpose
    ocsphelper  OCSP helper

看起来没问题吗?

2 个答案:

答案 0 :(得分:0)

您可以尝试使用WebSocket中的通用名称而不是IP。

var socket = WebSocket(url: URL(string: "wss://192.168.1.130:6223")!, protocols: [])

您可以使用命令

验证证书中的通用名称。
openssl x509 -in <certificate file> -text

使用以下命令验证SSL握手

openssl s_client -host <common name mentioned in the cert> -port <port> -cert <client_cert file> -key <client_key file> -CAfile <ca_cert file>

答案 1 :(得分:0)

在一个旧的swift应用程序中,我使用自签名证书公开的REST API和WS遇到相同的问题。

Websocket协议嵌入在HTTP / S协议中,也是握手协议。

因此生成证书.cert: 回声-n | openssl s_client -connect 您的网址:443 | sed -ne'/ -BEGIN CERTIFICATE-/,/-END CERTIFICATE- / p'> name_youwant .cert

将.cert文件导入将使用该文件的应用程序资产中。

在建立Websocket连接的类中,实现URLSessionDelegate。

然后使用此逻辑来验证自签名证书:

注意: NSBundle.mainBundle()。pathForResource(Config.certificate,ofType:“ .cert”)-> Config.certificate是指示文件名的静态字符串。

    // uncomment if self signed certificate is used on the backend
    public func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
        let serverTrust = challenge.protectionSpace.serverTrust
        let certificate = SecTrustGetCertificateAtIndex(serverTrust!, 0)
        let certificateData = SecCertificateCopyData(certificate!)
        let remoteCertificateData = certificateData as NSData
        let cerPath = NSBundle.mainBundle().pathForResource(Config.certificate, ofType: ".cert")

        let localCertData = NSData(contentsOfFile: cerPath!)!
        if localCertData.isEqualToData(remoteCertificateData) {
            completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential,NSURLCredential(forTrust:
                challenge.protectionSpace.serverTrust!))
        }else{
            completionHandler(NSURLSessionAuthChallengeDisposition.CancelAuthenticationChallenge,nil)
       }

    }

希望这会有所帮助。 问候