对于任何域,Java SSL 握手总是获得 "PKIX path building failed"

标签 java ssl

我在idea中构建gradle项目时收到这个错误信息:

      > Could not resolve io.spring.gradle:dependency-management-plugin:1.0.6.RELEASE.
         > Could not get resource 'https://plugins.gradle.org/m2/io/spring/gradle/dependency-management-plugin/1.0.6.RELEASE/dependency-management-plugin-1.0.6.RELEASE.pom'.
            > Could not HEAD 'https://plugins.gradle.org/m2/io/spring/gradle/dependency-management-plugin/1.0.6.RELEASE/dependency-management-plugin-1.0.6.RELEASE.pom'.
               > sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

我发现java中的所有ssl handshack都报同样的错误。

我使用 SSLPoke检查一些域,例如 stackoverflow.com、github.com,它们都返回相同的错误消息:“PKIX 路径构建失败”。但是我可以在浏览器上访问这个网站而不会出错。

我尝试将jdk从jdk11换成jdk8,再尝试重新安装jdk,也是一样的结果。我通过keytool -list命令检查了默认的jdk keystore,看起来没问题。

我尝试调试,发现证书看起来很奇怪,它在证书链中只有一个证书,并且 Issuer 始终是 CN=GlobalSign Root CA, C=EN,无论哪个领域。如stackoverflow.com:

[
[
  Version: V3
  Subject: CN=*.stackexchange.com
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

  Key:  Sun RSA public key, 1024 bits
  modulus: 129343236870246922217917428341848371602010941604981692235450252202393431416169367447480541321401904173442212978999107322095875009215075266308069463921433338673265672174736174633404814882397952490528363553362969976277321592285699339620492251079789709609773064124868826755702755848122392099215387700370904957487
  public exponent: 65537
  Validity: [From: Fri Jul 26 22:38:33 CST 2019,
               To: Thu Oct 24 22:38:33 CST 2019]
  Issuer: CN=GlobalSign Root CA, C=EN
  SerialNumber: [    bae8be0e 04cb0e2b 0e83d26f c22ba1e7]

Certificate Extensions: 3
[1]: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:false
  PathLen: undefined
]

[2]: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
  serverAuth
  clientAuth
]

[3]: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  DNSName: *.askubuntu.com
  DNSName: *.blogoverflow.com
  DNSName: *.mathoverflow.net
  DNSName: *.meta.stackexchange.com
  DNSName: *.meta.stackoverflow.com
  DNSName: *.serverfault.com
  DNSName: *.sstatic.net
  DNSName: *.stackexchange.com
  DNSName: *.stackoverflow.com
  DNSName: *.stackoverflow.email
  DNSName: *.superuser.com
  DNSName: askubuntu.com
  DNSName: blogoverflow.com
  DNSName: mathoverflow.net
  DNSName: openid.stackauth.com
  DNSName: serverfault.com
  DNSName: sstatic.net
  DNSName: stackapps.com
  DNSName: stackauth.com
  DNSName: stackexchange.com
  DNSName: stackoverflow.blog
  DNSName: stackoverflow.com
  DNSName: stackoverflow.email
  DNSName: stacksnippets.net
  DNSName: superuser.com
]

]
  Algorithm: [SHA256withRSA]
  Signature:
0000: B5 35 45 AA 8D 99 FF F1   3F 5D CA 94 6D 5F 6A 12  .5E.....?]..m_j.
0010: D2 39 0E 66 1D 11 63 80   12 0C A1 2D A7 CA A7 39  .9.f..c....-...9
0020: 36 4B A4 12 45 AD A8 4D   E5 1E DD 7B AF A9 10 CD  6K..E..M........
0030: ED 5B 15 76 F2 49 41 F8   AB 82 67 5D E8 09 0A 65  .[.v.IA...g]...e
0040: 7D BC 22 C5 53 7D DD 32   15 9E 88 92 FB 35 C2 C8  ..".S..2.....5..
0050: 86 E0 53 BF 32 72 DA FA   CE 27 A0 BA 78 5F DA B2  ..S.2r...'..x_..
0060: CA C3 8B 14 0B C5 EF E1   4D 96 8F BF 4A AC B0 DB  ........M...J...
0070: 24 5E 20 7C 32 51 58 93   36 0B 1A 2A BB 88 A3 9B  $^ .2QX.6..*....
0080: DF 6F B4 F1 25 CD B8 C6   C1 1D 19 BD A7 54 27 73  .o..%........T's
0090: 56 A8 5D 78 13 E6 86 00   59 E2 32 34 34 28 6D 4F  V.]x....Y.244(mO
00A0: 30 39 F6 3A 2E 43 1F E6   7B 43 57 C2 79 E5 87 4C  09.:.C...CW.y..L
00B0: CB 9E 95 6D 99 6D 46 AD   FA 7D 74 BA 12 D9 D0 8B  ...m.mF...t.....
00C0: 93 B7 49 E4 61 FD 4B 73   00 FA 0E 61 9A 4E DA C1  ..I.a.Ks...a.N..
00D0: D3 B9 45 B1 79 13 BB 90   02 98 24 E7 4D 31 01 52  ..E.y.....$.M1.R
00E0: 1F 38 47 0B 4E 4C E0 91   2A 8A 05 6E 20 89 81 E3  .8G.NL..*..n ...
00F0: 3B E3 60 D5 70 DF 28 D3   58 E7 D6 FF A6 CA 1D B6  ;.`.p.(.X.......

]

不同于普通证书:

  • key 长度。正常是 2048 位,而不是 1024 位。
  • 发行人。正常是 CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US
  • 证书扩展。 Normal 有 9 个扩展名,而不是 3 个。
  • 模数、序列号、签名。它们的值与正常值不同。
  • 普通证书在证书链中有一个中间证书,颁发者是CN=DST Root CA X3, O=Digital Signature Trust Co.

那么,如何才能找到问题的真正原因,并解决问题。

最佳答案

Meta:还不是答案,但需要空间来响应数据

旁白:我假设您处于 +8 时区。 PCAP 是 09-18 01:43:00-01 和 01:49:52-54 Z 而 Java 日志时间戳是 09-18 09:42:59-43:01 和 09:49:51-54 CST。

首先,Java 日志。在第 3652 行的成功日志中,ServerHello 选择 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 并同意扩展 renegotiation_info server_name ec_point_formats status_request extended_master_secret; 这与我测试中的真实 stackoverflow 服务器一致。在 3651 处的失败日志中, 它选择 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 并同意仅 renegotiation_info ec_point_formats, 这是完全不同的行为。然后我们看到不同的证书, success.txt 获得正确的叶证书(在 Let's Encrypt 下)和链证书(在 DST 下), 和 fail.txt 在“CN=GlobalSign Root CA, C=EN”下获取虚假证书,缺少大多数扩展名,并且没有链。

但是对于 PCAP:

See line 3638 in the fail log, the raw read bytes is different to the first five bytes of Transport Layer Security in the server hello response. In success log, they are the same.

这不是唯一的区别。虽然时间相符, 您的 fail.PCAP 与您的 fail.txt 完全不匹配。最重要的是,它不会失败—— 它接收到正确的证书链(Let's Encrypt + DST)并成功完成握手。 更详细:

  • ClientHello 非常不同。它提供最大的 TLS1.2,而不是(您的)Java 提供的 TLS1.3。 它有不同的密码套件列表和不同的扩展名(1.2 和 1.3 必须如此), 其中Heartbeat和ticket都是Java不支持的。

  • ServerHello 更短(记录头 16 03 03 00 45 与 fail.txt 中的 16 03 03 00 59 或 success.txt 中的 16 03 03 00 65, 正如您注意到的那样)因为它提供了票证并且服务器同意了,因此服务器不提供 session ID。

  • (如上)它获得了良好的证书,以及 CertStatus ServerKX ServerDone, 并继续发送 ClientKX CCS Finished 并接收票证 CCS Finished——即成功。

  • 您的客户端很快(但不是立即)RST,但不发送(或接收)任何数据;这是 Windows 程序在不执行关机(可能是因为被杀死)的情况下关闭或 Unix 程序显式设置 linger=0(这是不寻常的)的行为。

我还注意到 fail.PCAP 连接转到 151.101.65.69 但 success.PCAP 转到 151.101.193.69。 这两个地址(以及其他两个)对于 stackoverflow.com 都是有效的,但通常是连接 像这样在短时间内从同一台机器解析并使用相同的地址。

仔细查看您为 fail.PCAP 所做的操作,看看您是否可以获得实际上是失败案例的 PCAP。 实际上,这里产生了一个想法。 你有杀毒软件或其他“端点保护”吗?这可能会在传出连接离开你的机器之前拦截它,这样程序 (Java) 甚至可以看到伪造的证书尽管正确 证书实际上是从网络中获取的。但是它拦截一个连接而不拦截另一个连接仍然需要有一个原因。

关于对于任何域,Java SSL 握手总是获得 "PKIX path building failed",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57864013/

相关文章:

java - 执行问题

java - 我有 5 个字符串,有些正在动态变化,但有些不能

java - 如何在运行后保持应用程序窗口处于 Activity 状态?

java - CXF JAVA 消息截断

Java HTTPS 代理/重定向服务器

security - 可以在没有 SSL 的情况下设计和测试安全的 Web 应用程序吗?

java - 从字符串中获取枚举索引?

apache - 对某些页面强制使用 https,对所有其他页面强制使用 http

google-chrome - 谷歌浏览器不支持 Mac 钥匙串(keychain)设置

ssl - 由于缺少本地证书路径,Laravel Cashier 无法连接到 Homestead 中的 Stripe