Java 如何解决;“没有通用的密码套件”;在SSL握手过程中?

Java 如何解决;“没有通用的密码套件”;在SSL握手过程中?,java,tomcat,ssl,Java,Tomcat,Ssl,我正在通过Tomcat8+Java8构建一个B2B服务。 但是我的一个客户无法使用SSL连接到我的服务。 添加SSL调试参数“-Djavax.net.debug=SSL”后,我看到错误消息: Is initial handshake: true Is secure renegotiation: false Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 for TLSv1 Ignoring unsu

我正在通过Tomcat8+Java8构建一个B2B服务。 但是我的一个客户无法使用SSL连接到我的服务。 添加SSL调试参数“-Djavax.net.debug=SSL”后,我看到错误消息:

Is initial handshake: true
Is secure renegotiation: false
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 for TLSv1.1
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 for TLSv1.1
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 for TLSv1.1
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1.1
https-jsse-nio-8445-exec-9, READ: SSLv3 Handshake, length = 62
*** ClientHello, TLSv1
RandomCookie:  GMT: 1490342314 bytes = { 192, 161, 228, 31, 66, 175, 222, 13, 79, 128, 217, 81, 18, 152, 169, 58, 114, 35, 201, 201, 147, 74, 131, 2, 213, 145, 181, 76 }
Session ID:  {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, Unknown 0xff:0x3, SSL_RSA_WITH_RC4_128_MD5]
Compression Methods:  { 0 }
Extension renegotiation_info, renegotiated_connection: <empty>
***
%% Initialized:  [Session-7, SSL_NULL_WITH_NULL_NULL]
https-jsse-nio-8445-exec-9, fatal error: 40: no cipher suites in common
javax.net.ssl.SSLHandshakeException: no cipher suites in common
初始握手是否为true
是否安全重新谈判:错误
忽略不受支持的密码套件:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 for TLSv1
忽略不受支持的密码套件:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 for TLSv1
忽略不支持的密码套件:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 for TLSv1
忽略不支持的密码套件:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1
忽略不支持的密码套件:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 for TLSv1.1
忽略不支持的密码套件:TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 for TLSv1.1
忽略不支持的密码套件:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 for TLSv1.1
忽略不支持的密码套件:TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 for TLSv1.1
https-jsse-nio-8445-exec-9,读为:SSLv3握手,长度=62
***ClientHello,TLSv1
RandomCookie:GMT:1490342314字节={192、161、228、31、66、175、222、13、79、128、217、81、18、152、169、58、114、35、201、201、147、74、131、2213、145、181、76}
会话ID:{}
密码套件:[SSL_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,SSL_RSA_WITH_3DES_EDE_CBC_SHA,未知0xff:0x3,SSL_RSA_WITH_RC4_128_MD5]
压缩方法:{0}
扩展重新协商\u信息,重新协商的\u连接:
***
%%已初始化:[会话-7,SSL\u NULL\u带\u NULL\u NULL]
https-jsse-nio-8445-exec-9,致命错误:40:没有通用密码套件
javax.net.ssl.SSLHandshakeException:没有通用的密码套件

如何解决错误?

以下是我解决问题的经验分享

  • 启用SSL调试参数“-Djavax.net.debug=SSL”,发现错误为“无通用密码套件”

  • 在谷歌搜索了一些页面后,我安装了“Java Cryptography Extension(JCE)Unlimited Strength Judiction”,它在JVM级别添加了一些加密算法,例如:TLS_RSA_WITH_AES_256_CBC_SHA,但它没有解决问题。 java是一个有用的代码,它可以在JVM级别显示可用的密码套件

  • 我捕获了网络数据包并在wireshark中进行了分析,它显示在客户端发送ClientHello后,我的服务器立即断开了连接

  • 由于我的客户无法使用我的进行测试,我必须自己重现问题,以加快故障排除过程。然后我找到了代码SslPoke.java并对其进行了修改。它可以通过使用TLS版本或密码套件的不同组合来模拟客户端的请求。我可以自己模拟相同的错误日志,这很有帮助

  • 然后,在google上,我发现我可以在Tomcat的server.xml中指定密码套件,例如:

  • 我添加了配置,由SslPoke测试并通过,案例结束

    希望这些经验能帮助其他面临同样问题的人。 别忘了检查JVM/Web容器/App Server中的密码套件配置。。。 下面的代码也非常有用,感谢提供这些代码的专家

    致以最诚挚的问候,
    利昂

    代码:Ciphers.java,可从以下位置找到:

    公共类密码
    {
    公共静态void main(字符串[]args)
    抛出异常
    {
    SSLServerSocketFactory ssf=(SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
    字符串[]defaultCiphers=ssf.getDefaultCipherSuite();
    字符串[]availableCiphers=ssf.GetSupportedCipherSuite();
    TreeMap密码=新TreeMap();
    对于(int i=0;i

    公共类SslPoke{
    私有静态javax.net.ssl.SSLSocketFactory getFactorySimple()引发异常{
    SSLContext context=SSLContext.getInstance(“TLSv1”);
    init(null,null,null);
    返回context.getSocketFactory();
    }
    公共静态void main(字符串[]args){
    System.getProperties().setProperty(“javax.net.debug”、“ssl”);
    System.getProperties().setProperty(“https.cipherSuites”、“TLS_RSA_WITH_AES_256_CBC_SHA”);
    试一试{
    字符串urlStr=“https://:”;
    URL=新URL(urlStr);
    HttpsURLConnection连接=(HttpsURLConnection)url.openConnection();
    javax.net.ssl.SSLSocketFactory SSLSocketFactory=getFactorySimple();
    连接。设置插座工厂(sslSocketFactory);
    InputStream in=connection.getInputStream();
    while(in.available()>0){
    System.out.print(in.read());
    }
    System.out.println(“成功连接”);
    }捕获(异常){
    异常。printStackTrace();
    }
    }
    }
    
    以下是我解决这个问题的经验分享

  • 启用SSL调试参数“-Djavax.net.debug=SSL”,发现错误为“无通用密码套件”

  • 在谷歌搜索了一些页面后,我安装了“Java Cryptography Extension(JCE)Unlimited Strength Judiction”,它在JVM级别添加了一些加密算法,例如:TLS_RSA_WITH_AES_256_CBC_SHA,但它没有解决问题。 java是一个有用的代码,它可以在JVM级别显示可用的密码套件

  • 我捕获了网络数据包并在wireshark中进行了分析,它显示在客户端发送ClientHello后,我的服务器立即断开了连接

  • 由于我的客户无法使用my进行测试,我必须自己复制问题以加快故障排除过程。然后我找到了代码SslPoke.java并对其进行了修改。它可以通过使用TLS版本或密码套件的不同组合来模拟客户的请求。我还可以自己模拟相同的错误日志,这非常有帮助

  • 然后,在google上,我发现我可以在Tomcat的server.xml中指定密码套件,例如:

  • 
    
    public class Ciphers
    {
        public static void main(String[] args)
            throws Exception
        {
            SSLServerSocketFactory ssf = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
    
            String[] defaultCiphers = ssf.getDefaultCipherSuites();
            String[] availableCiphers = ssf.getSupportedCipherSuites();
    
            TreeMap ciphers = new TreeMap();
    
            for(int i=0; i<availableCiphers.length; ++i )
                ciphers.put(availableCiphers[i], Boolean.FALSE);
    
            for(int i=0; i<defaultCiphers.length; ++i )
                ciphers.put(defaultCiphers[i], Boolean.TRUE);
    
            System.out.println("Default\tCipher");
            for(Iterator i = ciphers.entrySet().iterator(); i.hasNext(); ) {
                Map.Entry cipher=(Map.Entry)i.next();
    
                if(Boolean.TRUE.equals(cipher.getValue()))
                    System.out.print('*');
                else
                    System.out.print(' ');
    
                System.out.print('\t');
                System.out.println(cipher.getKey());
            }
        }
    }
    
    public class SslPoke {
    
        private static javax.net.ssl.SSLSocketFactory getFactorySimple() throws Exception {
            SSLContext context = SSLContext.getInstance("TLSv1");
    
            context.init(null, null, null);
    
            return context.getSocketFactory();
    
        }
    
        public static void main(String[] args) {
            System.getProperties().setProperty("javax.net.debug", "ssl");
            System.getProperties().setProperty("https.cipherSuites", "TLS_RSA_WITH_AES_256_CBC_SHA");
    
            try {
                String urlStr ="https://<your host>:<your port>";
                URL url = new URL(urlStr);
    
                HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
    
                javax.net.ssl.SSLSocketFactory sslSocketFactory = getFactorySimple();
    
                connection.setSSLSocketFactory(sslSocketFactory);
                InputStream in = connection.getInputStream();
    
                while (in.available() > 0) {
                    System.out.print(in.read());
                }
                System.out.println("Successfully connected");
    
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
    }