1

我正在使用 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 failed (-9807) websocket is disconnected: 操作无法完成。(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

这看起来好吗?

4

2 回答 2

0

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

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

所以生成证书.cert:echo -n | openssl s_client -connect yoururl :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)
       }

    }

希望这可以帮助。问候,

于 2020-03-16T12:17:38.257 回答
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>
于 2020-03-15T16:35:31.187 回答