下载项目依赖项时,Maven抛出IllegalStateException(与SSL相关?)

时间:2016-05-11 15:31:43

标签: java maven ssl

我在ARM计算机上设置开发环境,使用以下版本的Java和Maven,都通过apt-get安装:

(xenial)craig@localhost:~$ mvn -version
Apache Maven 3.3.9
Maven home: /usr/share/maven
Java version: 1.8.0_91, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-8-openjdk-armhf/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "3.14.0", arch: "arm", family: "unix"

(xenial)craig@localhost:~$ java -version
openjdk version "1.8.0_91"
OpenJDK Runtime Environment (build 1.8.0_91-8u91-b14-0ubuntu4~16.04.1-b14)
OpenJDK Zero VM (build 25.91-b14, interpreted mode)

但是,当我在项目上运行mvn clean install时,它无法尝试下载 存在的POM文件。 (我可以在浏览器中访问它。)

堆栈跟踪非常大,但根似乎是:

Caused by: java.lang.IllegalStateException
    at sun.security.ec.ECDHKeyAgreement.deriveKey(Native Method)
    at sun.security.ec.ECDHKeyAgreement.engineGenerateSecret(ECDHKeyAgreement.java:130)
    at sun.security.ec.ECDHKeyAgreement.engineGenerateSecret(ECDHKeyAgreement.java:163)
    at javax.crypto.KeyAgreement.generateSecret(KeyAgreement.java:648)
    at sun.security.ssl.ECDHCrypt.getAgreedSecret(ECDHCrypt.java:101)
    at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:1067)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:348)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)

不幸的是,Maven失败了:

Caused by: org.eclipse.aether.resolution.ArtifactDescriptorException: Failed to read artifact descriptor for org.jacoco:jacoco-maven-plugin:jar:0.7.6.201602180812

堆栈以deriveKey()中抛出的异常结束。我在机器上错过了一些加密库吗?

这是新安装的Xenial(16.04 LTS)。

1 个答案:

答案 0 :(得分:9)

虽然安装Oracle JRE是一种简单的方法,但以下是您希望特别使用OpenJDK Zero VM的说明,无论是使用Maven,SSL,ECDH密钥协议还是以本机实现的任何其他加密方法OpenJDK默认加密提供程序中的代码。

我假设ECDHKeyAgreement.deriveKey方法失败了,因为它是一个本机方法,并且在Ubuntu for Raspberry Pi中打包的OpenJDK Zero VM无法处理它;我没有能力调试那个失败。

Ubuntu打包了用纯Java实现的BouncyCastle加密提供程序。你需要以通常的方式安装它:

sudo apt install libbcprov-java*

(这也安装了文档)

然后按照/usr/share/doc/libbcprov-java/README.Debian中的说明将其设为默认加密提供程序。具体来说,你需要从JRE的ext目录链接到提供者jar,所以做一个update-java-alternatives -l后跟(在我的情况下 - 我一直在使用Ubuntu 16.04 Raspberry Pi服务器安装中提供的默认值) - 特定的JRE目录可能会及时更改):

sudo ln -s /usr/share/java/bcprov.jar /usr/lib/jvm/java-1.8.0-openjdk-armhf/jre/lib/ext/bcprov.jar

然后编辑/usr/lib/jvm/java-1.8.0-openjdk-armhf/jre/lib/security/java.security文件(使用sudo调用编辑器),添加以下行:

security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider

...列出了加密提供程序,并将已加密提供程序的优先级加1,以便列表看起来类似于:

security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider
security.provider.2=sun.security.provider.Sun
security.provider.3=sun.security.rsa.SunRsaSign
security.provider.4=sun.security.ec.SunEC
security.provider.5=com.sun.net.ssl.internal.ssl.Provider
security.provider.6=com.sun.crypto.provider.SunJCE
security.provider.7=sun.security.jgss.SunProvider
security.provider.8=com.sun.security.sasl.Provider
security.provider.9=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.10=sun.security.smartcardio.SunPCSC

Java中的加密现在应该可以工作,尽管速度很慢。这是一个我用来确认它的示例程序,如果你不想使用Maven:

import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class URLGet {
        public static void main(String[] args) {
                try {
                        URL url = new URL(args[0]);
                        URLConnection urlConnection = url.openConnection();
                        try (
                                InputStream stream = urlConnection.getInputStream();
                        ) {
                                byte[] buf = new byte[4096];
                                int read;
                                while ((read = stream.read(buf, 0, buf.length)) > 0) {
                                        System.out.write(buf, 0, read);
                                }
                        }
                } catch (Exception e) {
                        e.printStackTrace(System.err);
                }
        }
}

将其指向任何https网址(例如java URLGet https://www.google.com/)以确认Java可以处理SSL。