我们有一个java应用程序,可以读取客户的公共日历--例如从google(https://calendar.google.com/calendar/ical/...)或icloud(webcal://p58-caldav.icloud.com/callshed/.)。
直到最近,这个功能还能正常工作,但现在它在icloud日历上失败了,并出现以下错误:
javax.net.ssl.SSLHandshakeException: Received fatal alert: decode_error
Google日历仍然有效。
我们的应用程序通过将webcal://交换为https://并在url上执行http get来读取icloud日历。
例如https://p58-caldav.icloud.com/published/2/MTg3MDA3MjYwMTE4NzAwN1KPAcrTfGuhFJXbGYJ9wEYJFNzP10cp8mw6gSLjUVU_
假设在浏览器中点击这个url成功返回一个有效的icalcms(ics)结果,我们首先想到的是,当在jvm中运行时,这个端点的根ca证书不在jvm的密钥库中。
我们使用以下命令获取此端点的证书:
openssl s_client -servername p58-caldav.icloud.com -host p58-caldav.icloud.com -port 443 -prexit -showcerts
然后将链中的两个证书添加到我们的密钥库中:
keytool -importcert -file apple-ist-ca-2-g1.crt -alias apple-ist-ca-2-g1 -trustcacerts -keystore <java home>/lib/security/cacerts -storepass <pass>
keytool -importcert -file caldav.icloud.com.crt -alias caldav.icloud.com -trustcacerts -keystore <java home>/lib/security/cacerts -storepass <pass>
我们还在测试用例中添加了代码,以验证jvm是否正在获取这些证书。
这不起作用,我们得到同样的错误。
我们正在运行openjdk版本“11.0.2”,所以我不相信有任何问题与SNI或失踪密码(虽然我可能是错的!)
下面这个非常简单的代码示例再现了错误:
public class CalReader {
public static void main(String[] args) {
hitAPI("webcal://p58-caldav.icloud.com/published/2/MTg3MDA3MjYwMTE4NzAwN1KPAcrTfGuhFJXbGYJ9wEYJFNzP10cp8mw6gSLjUVU_");
}
private static void hitAPI(final String url) {
String cleaned = url.replace("webcal://", "https://").trim();
InputStream in = null;
try {
URL toUse = new URL(cleaned);
URLConnection conn = toUse.openConnection();
in = conn.getInputStream();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if (in != null) {
in.close();
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
添加ssl调试(-Djavax.NET.debug=ssl:handshake:verbose)并没有(在我看来)提供任何相关信息。但是,我承认我不是一个SSLMaven。
javax.net.ssl|DEBUG|01|main|2019-07-18 11:51:53.042 AEST|ClientHello.java:651|Produced ClientHello handshake message (
"ClientHello": {
"client version" : "TLSv1.2",
"random" : "BC DF 54 80 F2 0B 9A F9 42 17 4A FF B9 B5 65 22 C4 9E 19 63 0A 88 81 1F 84 2A 74 2D 40 40 F2 F0",
"session id" : "A9 21 0D FE 9B 8E 9F B8 53 17 60 09 D4 B2 C8 EE BE FD 7F AC 93 57 12 4B 47 BA FF A9 7A DF C4 EF",
"cipher suites" : "[TLS_AES_128_GCM_SHA256(0x1301), TLS_AES_256_GCM_SHA384(0x1302), TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(0xC02C), TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(0xC02B), TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030), TLS_RSA_WITH_AES_256_GCM_SHA384(0x009D), TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384(0xC02E), TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384(0xC032), TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(0x009F), TLS_DHE_DSS_WITH_AES_256_GCM_SHA384(0x00A3), TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(0xC02F), TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C), TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256(0xC02D), TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256(0xC031), TLS_DHE_RSA_WITH_AES_128_GCM_SHA256(0x009E), TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(0x00A2), TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384(0xC024), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384(0xC028), TLS_RSA_WITH_AES_256_CBC_SHA256(0x003D), TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384(0xC026), TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384(0xC02A), TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(0x006B), TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(0x006A), TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA(0xC00A), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(0xC014), TLS_RSA_WITH_AES_256_CBC_SHA(0x0035), TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA(0xC005), TLS_ECDH_RSA_WITH_AES_256_CBC_SHA(0xC00F), TLS_DHE_RSA_WITH_AES_256_CBC_SHA(0x0039), TLS_DHE_DSS_WITH_AES_256_CBC_SHA(0x0038), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256(0xC023), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256(0xC027), TLS_RSA_WITH_AES_128_CBC_SHA256(0x003C), TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256(0xC025), TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256(0xC029), TLS_DHE_RSA_WITH_AES_128_CBC_SHA256(0x0067), TLS_DHE_DSS_WITH_AES_128_CBC_SHA256(0x0040), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA(0xC009), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(0xC013), TLS_RSA_WITH_AES_128_CBC_SHA(0x002F), TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA(0xC004), TLS_ECDH_RSA_WITH_AES_128_CBC_SHA(0xC00E), TLS_DHE_RSA_WITH_AES_128_CBC_SHA(0x0033), TLS_DHE_DSS_WITH_AES_128_CBC_SHA(0x0032)]",
"compression methods" : "00",
"extensions" : [
]
}
)
javax.net.ssl|DEBUG|01|main|2019-07-18 11:51:53.046 AEST|Alert.java:232|Received alert message (
"Alert": {
"level" : "fatal",
"description": "decode_error"
}
)
我们刚刚在Java 8环境中尝试了这一点,它像预期的那样工作。作为一个快速测试,我们将java 8环境的caceton复制到java 11环境中,然而,它仍然不工作。Java 8环境中还有什么可以让它工作的?
这很难确定,但似乎是在过去的2-4周左右发生的。我们有证据表明在6月24日成功读取了iCloud日历,我们从7月4日开始看到上述错误。
我们已经尝试了多个icloud日历,每个都得到了相同的结果,所以它似乎与日历本身无关。
更新
我们强制使用了TLS1.2,它可以正常工作。对于上面的示例:
java -Dhttps.protocols=TLSv1.2 CalReader
这就引出了一个问题,苹果终端是否与TLS1.3有问题?或者是别的什么?
我们确实发现了一篇文章,指出了Java 11(https://webtide.com/openjdk-11-and-tls-1-3-issues/)中的TLS1.3的问题,但我们已经尝试了Java 12版本,没有成功,所以我不认为这是问题。
因此,我们现在必须决定是强制使用TLS1.2还是继续寻找另一种解决方案。
2条答案
按热度按时间pu82cl6c1#
我昨天在尝试连接到https://apple.com:443的Java应用程序中遇到了同样的问题。我发现在不同的(Docker)操作系统上使用不同的JDK解决了这个问题。在我的具体案例中,Alpine上的OpenJDK不工作,但其他Dockerized OpenJDK(如
adoptopenjdk/openjdk11
)工作得很好。izkcnapc2#
我在连接apple cloud url时遇到了
Received fatal alert: decode_error
。我能够通过显式地将协议设置为TLS 1.2
来修复它。例如:在
kotlin
中,如下所示更新您的spring RestTemplate
,