对于 SMACK 4.3.4 如何更新客户端连接到服务器所需的默认证书?

For SMACK 4.3.4 How do I update a default certificate needed for client connection to server?

我使用 SMACK 4.3.4 编写了一个 Android 应用程序。直到今天,当我开始出现连接错误时,一切都运行良好。

我正在使用 public 在线 XMPP 服务器进行测试 (chatserver.space)。到目前为止,我还没有对证书做任何事情。这一切 "just worked"。很明显某处有一些默认证书已过期(请参阅下面堆栈跟踪的 Caused by: java.security.cert.CertPathValidatorException: timestamp check failed 部分),我只是不明白它在哪里以及我需要做什么才能正确地推迟日期。

这是来自我的应用程序的代码(标准 SMACK 连接内容):

public void connect() throws Exception {
    Timber.d("Lifecycle: XMPPConnectionMgr connect() attempted HOST: %s, PORT: %d, DOMAIN: %s", XMPP_HOST, XMPP_PORT, XMPP_DOMAIN);
    if (xmppConnection == null) {
        XMPPTCPConnectionConfiguration.Builder connConfigBuilder = XMPPTCPConnectionConfiguration.builder();
        try {

            connConfigBuilder
                    .setHost(XMPP_HOST)         // Name of your Host
                    .setPort(XMPP_PORT)         // Your Port for accepting c2s connection
                    .setXmppDomain(XMPP_DOMAIN)
                    .setSecurityMode(XMPPTCPConnectionConfiguration.SecurityMode.required);

            xmppConnection = new XMPPTCPConnection(connConfigBuilder.build());
            xmppConnection.addConnectionListener(this);

            Set<String> blacklist = SASLAuthentication.getBlacklistedSASLMechanisms();
            Timber.d("Lifecycle: Blacklist contents: %s", blacklist.toString());
            Map<String,String> registered = SASLAuthentication.getRegisterdSASLMechanisms();
            Timber.d("Lifecycle: registered SASLAuthentication mechanisms: %s", registered.toString());

        } catch (XmppStringprepException e) {
            Timber.d("XMPPConnectionMgr could not connect to XMPP Server: %s", e.getMessage());
            throw new Exception(String.format(InTouch.getInstance().getApplicationContext().getString(R.string.exception_communications_connection),
                    e.getMessage()));
        }
    }
    try {
        if ( !xmppConnection.isConnected() ) {
            xmppConnection.connect();
        }
    } catch (SmackException e) {
        Timber.d("XMPPConnectionMgr got Exception trying to connect to XMPP Server: %s", e.getMessage());
        throw new Exception(String.format(InTouch.getInstance().getApplicationContext().getString(R.string.exception_communications_connection),
                e.getMessage()));
    } catch (IOException e) {
        Timber.d("XMPPConnectionMgr got IOException trying to connect to XMPP Server: %s", e.getMessage());
        throw new Exception(String.format(InTouch.getInstance().getApplicationContext().getString(R.string.exception_communications_connection),
                e.getMessage()));
    } catch (XMPPException e) {
        Timber.d("XMPPConnectionMgr got Exception trying to connect to XMPP Server: %s", e.getMessage());
        throw new Exception(String.format(InTouch.getInstance().getApplicationContext().getString(R.string.exception_communications_connection),
                e.getMessage()));
    } catch (InterruptedException e) {
        Timber.d("XMPPConnectionMgr got InterruptedException trying to connect to XMPP Server: %s", e.getMessage());
        throw new Exception(String.format(InTouch.getInstance().getApplicationContext().getString(R.string.exception_communications_connection),
                e.getMessage()));
    }
}

完整的堆栈跟踪如下:

2019-07-22 21:01:46.942 1511-1929/com.reddragon.intouch W/AbstractXMPPConnection: Connection XMPPTCPConnection[not-authenticated] (0) closed with error
    javax.net.ssl.SSLHandshakeException: Chain validation failed
        at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:361)
        at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:690)
        at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:652)
        at org.jivesoftware.smack.tcp.XMPPTCPConnection.initReaderAndWriter(XMPPTCPConnection.java:703)
        at org.jivesoftware.smack.tcp.XMPPTCPConnection.proceedTLSReceived(XMPPTCPConnection.java:853)
        at org.jivesoftware.smack.tcp.XMPPTCPConnection.access00(XMPPTCPConnection.java:155)
        at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1171)
        at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access00(XMPPTCPConnection.java:1092)
        at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.run(XMPPTCPConnection.java:1112)
        at java.lang.Thread.run(Thread.java:764)
     Caused by: java.security.cert.CertificateException: Chain validation failed
        at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:788)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:612)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:633)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:678)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:499)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:422)
        at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:343)
        at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
        at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:88)
        at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:203)
        at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:607)
        at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
        at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357)
        at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:690) 
        at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:652) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection.initReaderAndWriter(XMPPTCPConnection.java:703) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection.proceedTLSReceived(XMPPTCPConnection.java:853) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection.access00(XMPPTCPConnection.java:155) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1171) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access00(XMPPTCPConnection.java:1092) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.run(XMPPTCPConnection.java:1112) 
        at java.lang.Thread.run(Thread.java:764) 
     Caused by: java.security.cert.CertPathValidatorException: timestamp check failed
        at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:133)
        at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:225)
        at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:143)
        at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79)
        at com.android.org.conscrypt.DelegatingCertPathValidator.engineValidate(DelegatingCertPathValidator.java:44)
        at java.security.cert.CertPathValidator.validate(CertPathValidator.java:301)
        at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:784)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:612) 
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:633) 
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:678) 
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:499) 
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:422) 
        at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:343) 
        at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94) 
        at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:88) 
        at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:203) 
        at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:607) 
        at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method) 
        at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357) 
        at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:690) 
        at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:652) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection.initReaderAndWriter(XMPPTCPConnection.java:703) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection.proceedTLSReceived(XMPPTCPConnection.java:853) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection.access00(XMPPTCPConnection.java:155) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1171) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access00(XMPPTCPConnection.java:1092) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.run(XMPPTCPConnection.java:1112) 
        at java.lang.Thread.run(Thread.java:764) 
     Caused by: java.security.cert.CertificateExpiredException: Certificate expired at Mon Jul 22 12:04:58 MDT 2019 (compared to Mon Jul 22 21:01:46 MDT 2019)
        at com.android.org.conscrypt.OpenSSLX509Certificate.checkValidity(OpenSSLX509Certificate.java:244)
        at sun.security.provider.certpath.BasicChecker.verifyTimestamp(BasicChecker.java:194)
        at sun.security.provider.certpath.BasicChecker.check(BasicChecker.java:144)
        at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:125)
        at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:225) 
        at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:143) 
        at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79) 
        at com.android.org.conscrypt.DelegatingCertPathValidator.engineValidate(DelegatingCertPathValidator.java:44) 
        at java.security.cert.CertPathValidator.validate(CertPathValidator.java:301) 
        at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:784) 
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:612) 
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:633) 
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:678) 
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:499) 
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:422) 
        at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:343) 
        at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94) 
        at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:88) 
        at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:203) 
        at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:607) 
        at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method) 
        at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357) 
        at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:690) 
        at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:652) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection.initReaderAndWriter(XMPPTCPConnection.java:703) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection.proceedTLSReceived(XMPPTCPConnection.java:853) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection.access00(XMPPTCPConnection.java:155) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1171) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access00(XMPPTCPConnection.java:1092) 
        at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.run(XMPPTCPConnection.java:1112) 
        at java.lang.Thread.run(Thread.java:764) 

查看openssl的输出:

wojtek@atlantiscity.local ~ $ openssl s_client -connect xmpp.chatserver.space:5222 -xmpphost chatserver.space < /dev/null -starttls xmpp | openssl x509 -noout -dates
depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = chatserver.space
verify return:1
poll error

notBefore=Jul 22 06:45:13 2019 GMT
notAfter=Oct 20 06:45:13 2019 GMT

看起来他们刚刚更新了他们的证书,所以您很可能从服务器获得了过时的证书(如 CertPathValidatorException: timestamp check failed 所示)。不幸的是,在这种情况下您无能为力 - 服务器所有者必须更新服务器上的证书

您可以绕过证书验证,但*这非常,非常令人气馁*(因此我不会详细说明如何做到这一点)