不支持的曲线:Java 应用上的 1.2.840.10045.3.1.7

Unsupported curve: 1.2.840.10045.3.1.7 on Java app

我有一个 Java 8 应用程序在连接 ldaps 或 https 服务器时引发以下异常:

Caused by: javax.net.ssl.SSLHandshakeException:
    Unsupported curve: 1.2.840.10045.3.1.7

我的客户端环境是:

Alpine Linux 3.5 on a Docker container
OpenJDK 1.8.0_111
Wildfly 10.1.0.Final

如果我从以下位置连接,我可以解决这个问题:

但是如果我从以下位置连接总是会失败:

有什么建议可以解决我的 Alpine Linux 安装上的这个问题吗?

TL,DR:来自 Alpine 的 OpenJDK 8 包不支持使用椭圆曲线的密码,例如 ECDHE。在 Java 选项上使用 -Dcom.sun.net.ssl.enableECC=false 以请求 OpenJDK 不要使用此类密码。

这个漂亮的 Atlassian paper 描述了如何使用以下代码从 JVM 列出所有默认和可用的密码:

import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import javax.net.ssl.SSLServerSocketFactory;

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());
        }
    }
}

运行 来自 Alpine 3.5 的 OpenJDK 8 上的这段代码没有列出任何 ECDHE 密码,另一方面,这段相同的代码列出了安装在 CentOS 7 机器上的 OpenJDK 8 中的几个这样的密码.

出于某种原因,使用椭圆曲线的密码作为 Wildfly 应用程序上的可用密码从客户端发送到服务器。在 Wildfly 之外 - 例如 java SomeClassjava -jar some.jar 这些密码不会发送并且通信有效。在 Java 选项上添加 -Djavax.net.debug=all 可以观察到这种行为。

Alpine Linux 3.5 的 openjdk8-jre-base 包 8.111.14-r1 不包含 libsunec.so,SunEC 提供程序查找的库,但 Alpine Linux 3.3 (8.92.14-r0) 和 3.4 (8.111.14-r0) 可以(请参阅 this package search). I've opened Alpine issue #6809

解决此问题的最简单方法可能是回滚到 Alpine 3.4。或者,您可以在 3.5 中安装 3.4 版本的 openjdk8-jre-base,但是如果您走这条路,您可能 运行 会遇到一些依赖问题。

如果您想使用 Alpine Linux 3.5 包,您可以让您的 java 应用程序使用备用 JCE 提供程序,例如 BouncyCastle。

如果您不需要 EC 加密,您可以禁用它,但请注意,这样做会使您的应用程序无法使用多个常见的 PFS 密码套件。