【问题标题】:Can't connect SSLSocket to server even with the right certificates即使使用正确的证书也无法将 SSLSocket 连接到服务器
【发布时间】:2020-05-06 17:12:02
【问题描述】:

我正在尝试使用 SSLSocket 使用 TLS 连接到应该已经具有正确证书的服务器。但是客户端一直在崩溃。

这是网站上的 SSL 检查器:

虽然这是代码(主机名和端口已更正):

val SSLSocketFactory = SSLSocketFactory.getDefault() as SSLSocketFactory
val socket: SSLSocket = factory.createSocket(address, port) as SSLSocket
socket.startHandshake()

当代码到达握手时,它会因以下错误而崩溃:

java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

知道为什么会发生这种情况吗?我使用 TLS 对服务器进行的另一个 HTTPS 调用运行良好,所以我认为问题不在于服务器(而且我看到的所有答案都有这种类型的回复)。

【问题讨论】:

  • 由于您尝试访问的域未知,我只能猜测:您正在尝试访问需要 SNI 的服务器。如果您不使用 SNI,您将获得与预期不同的证书,并且验证失败。通过 SSLLabs 检查您的域,以检查您的域是否需要 SNI 或是否存在其他问题。
  • 我的总体评分为 A。看来我们不使用 SNI,因为我们现在只有一个域和一个证书。
  • 很难说到底发生了什么。如果您可以共享域,则可以仔细查看。请注意,仅仅因为您只有一个域并不意味着您不需要 SNI - 这取决于服务器的设置。但是,如果 ssllabs 对 SNI 只字未提,那么您可能就不需要了。
  • 我不认为 SNI 是问题所在。也许我必须将 GoDaddy 的证书添加到客户端?现在我使用的是默认值,仅此而已

标签: android sockets ssl tls1.2


【解决方案1】:

问题是我需要在打开 SSL 套接字连接的客户端中固定证书。

有关更通用的指南,请参阅有关 SSL pinning on Android 的指南。尽管该指南适用于 HTTPS 连接,而不是 Socket。

对于套接字,我做了以下工作:

fun run() {
    val trustGodaddyCertificate = loadTrustManagers()

    val sslContext = SSLContext.getInstance("SSL")
    sslContext.init(null, trustGodaddyCertificate, SecureRandom())

    val socket = sslContext.socketFactory.createSocket(address, port)

    // use the socket
}

private fun loadTrustManagers(): Array<out TrustManager>? {
    val certificateFactory: CertificateFactory = CertificateFactory.getInstance("X.509")
    val caInput: InputStream = BufferedInputStream(resources.openRawResource(R.raw.server_godaddy_certificate))
    caInput.use {
        val certificate = certificateFactory.generateCertificate(caInput)

        val keyStoreType: String = KeyStore.getDefaultType()
        val keyStore: KeyStore = KeyStore.getInstance(keyStoreType)
        keyStore.load(null, null)
        keyStore.setCertificateEntry("ca", certificate)

        val tmfAlgorithm: String = TrustManagerFactory.getDefaultAlgorithm()
        val trustManagerFactory: TrustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm)
        trustManagerFactory.init(keyStore)

        return trustManagerFactory.trustManagers
    }
}

简而言之,我已将 GoDaddy 的 .crt 证书保存在原始资源中。我已经加载了它并创建了一个使用它的 TrustManager。我已经把它放在客户允许的证书中。这使一切正常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-27
    • 2014-04-19
    • 1970-01-01
    • 2020-05-17
    相关资源
    最近更新 更多