jlink创建的运行时出现SSLHandshakeException异常

37

我有一个 Dropwizard 应用程序,使用标准的 JRE 可以正常运行。

我尝试使用 jlink 创建一个更小的运行时:

/Library/Java/JavaVirtualMachines/jdk-11.jdk/Contents/Home/bin/jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.base,java.compiler,java.desktop,java.instrument,java.logging,java.management,java.naming,java.scripting,java.security.jgss,java.sql,java.xml,jdk.attach,jdk.jdi,jdk.management,jdk.unsupported --output jre

如果我使用jlink创建的运行时环境来运行它,连接redis(redis前面有stunnel)时会抛出此错误。

ERROR [2019-03-31 09:12:20,080] com.company.project.core.WorkerThread: Failed to process message.
! javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
! at java.base/sun.security.ssl.Alert.createSSLException(Unknown Source)
! at java.base/sun.security.ssl.Alert.createSSLException(Unknown Source)
! at java.base/sun.security.ssl.TransportContext.fatal(Unknown Source)
! at java.base/sun.security.ssl.Alert$AlertConsumer.consume(Unknown Source)
! at java.base/sun.security.ssl.TransportContext.dispatch(Unknown Source)
! at java.base/sun.security.ssl.SSLTransport.decode(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.decode(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl.ensureNegotiated(Unknown Source)
! at java.base/sun.security.ssl.SSLSocketImpl$AppOutputStream.write(Unknown Source)
! at redis.clients.jedis.util.RedisOutputStream.flushBuffer(RedisOutputStream.java:52)
! at redis.clients.jedis.util.RedisOutputStream.flush(RedisOutputStream.java:133)
! at redis.clients.jedis.Connection.flush(Connection.java:300)
! ... 9 common frames omitted
! Causing: redis.clients.jedis.exceptions.JedisConnectionException: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
! at redis.clients.jedis.Connection.flush(Connection.java:303)
! at redis.clients.jedis.Connection.getStatusCodeReply(Connection.java:235)
! at redis.clients.jedis.BinaryJedis.auth(BinaryJedis.java:2225)
! at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:119)
! at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:888)
! at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:432)
! at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:361)
! at redis.clients.jedis.util.Pool.getResource(Pool.java:50)
! ... 2 common frames omitted
! Causing: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
! at redis.clients.jedis.util.Pool.getResource(Pool.java:59)
! at redis.clients.jedis.JedisPool.getResource(JedisPool.java:234)

stunnel服务器的日志显示:

redis_1  | 09:12:20 stunnel.1 | 2019.03.31 09:12:20 LOG7[23]: TLS alert (write): fatal: handshake failure
redis_1  | 09:12:20 stunnel.1 | 2019.03.31 09:12:20 LOG3[23]: SSL_accept: 141F7065: error:141F7065:SSL routines:final_key_share:no suitable key share
redis_1  | 09:12:20 stunnel.1 | 2019.03.31 09:12:20 LOG5[23]: Connection reset: 0 byte(s) sent to TLS, 0 byte(s) sent to socket

jlink是否会忽略某些加密算法?


10
嗯,如果我添加jdk.crypto.ec,它就可以工作——如果jdeps忽略了那个,那么它为什么会被省略,如果有其他省略的部分,会有哪些? - rich
3
我记得JCA提供程序是扩展程序:库中没有直接依赖它们,必须将它们显式地放入类路径中(就像其他典型的适配器扩展程序:数据库连接器等)。 - jjmontes
1
这就是为什么模块是一个麻烦的问题 - Kowlown
3个回答

47

正如rich在评论中提到的

嗯。如果我添加jdk.crypto.ec,它就可以正常工作了 - 如果那个被省略了,是否还有其他被省略的?

将jdk.crypto.ec添加到模块列表中解决了问题。


6
所以你可以使用带有HTTPS支持但没有任何SSL/TLS/...实现的完好运行时,但只有在握手失败并显示含义难懂的错误信息时才会注意到。我明白为什么会这样,但这肯定不方便,也不符合最小惊奇原则。 - Hendrik
7
这真的非常令人沮丧,这是解决方法。我的应用程序在JRE上部署了数月,然后突然失去了与服务器通信的能力(这意味着无法更新)。为什么他们不把这个包括进去呢? - Mgamerz
1
在OpenJDK11.0.9/Win64上,这会将JRE大小增加0.3 MiB。 - lapo
请注意,这也修复了“Received fatal alert: access_denied”错误。 - Asapha
1
这就是为什么每次我想要开始一个Java项目时,我都应该提醒自己,这将花费我14个小时来找到隐藏的瑰宝。非常感谢您的答案,它拯救了我,并帮助我意识到这是我在工作中做的最后一个基于Java的项目。 - smerkd

9

也可以在jlink命令中添加--bind-services(链接服务提供商模块及其依赖项)。但根据我的经验,这将使生成的运行时更大。但至少这是一个选项,可以快速找出观察到的问题是否由于缺少服务实现引起。


4

我还需要添加 jdk.crypto.ecjdk.crypto.cryptoki


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接