bigywater.tech
Java · 256

PKIX 证书路径验证:Java 如何判断证书链可信

Java 怎么判断一条证书链可信?缺中间证书、证书过期、CA 约束被违反会怎样?这篇用 keytool 造出一棵真实的证书树,逐个用 CertPathValidator 验证,看每种失败的 reason 与出错的证书位置。

NO_TRUST_ANCHOR
缺中间证书或链不通向信任锚时的失败原因
PATH_TOO_LONG
pathlen:0 的 CA 下面再挂子 CA 的失败原因
UNDETERMINED_REVOCATION_STATUS
证书没有撤销信息而撤销检查开启时的失败原因

链的构成与信任锚

实测 · 本机执行输出
  证书链(叶子在前,不含根):leaf ← Demo Intermediate(pathlen:0)← Demo Root(信任锚)
  正常链 [leaf, ica],信任 root(撤销检查关闭)→ 通过,信任锚 = Demo Root,叶子的公钥算法 EC
  缺中间证书 [leaf],信任 root → CertPathValidatorException: Path does not chain with any of the trust anchors(原因 NO_TRUST_ANCHOR,出问题的证书在链中的下标 -1)
  链里把根也放进去 [leaf, ica, root],信任 root → 通过,信任锚 = Demo Root,叶子的公钥算法 EC
  链的顺序放反 [ica, leaf],信任 root → CertPathValidatorException: Path does not chain with any of the trust anchors(原因 NO_TRUST_ANCHOR,出问题的证书在链中的下标 -1)
  信任了另一个根 other → CertPathValidatorException: Path does not chain with any of the trust anchors(原因 NO_TRUST_ANCHOR,出问题的证书在链中的下标 -1)
  把中间证书当作信任锚(信任 ica,链只有 [leaf])→ 通过,信任锚 = Demo Intermediate,叶子的公钥算法 EC
  叶子的有效期:Sat Oct 03 18:49:18 CST 2026 ~ Fri Jul 30 18:49:18 CST 2027

有效期

实测 · 本机执行输出
  过期的叶子 [exp, ica],信任 root(今天)→ CertPathValidatorException: validity check failed(原因 EXPIRED,出问题的证书在链中的下标 0)
  同一个过期的叶子,把验证时间设在叶子自己的有效期内 Fri Sep 04 18:49:20 CST 2026(这时中间证书还没有生效)→ CertPathValidatorException: validity check failed(原因 NOT_YET_VALID,出问题的证书在链中的下标 1)
  正常链,把验证时间设成 400 天以后(叶子 300 天、中间证书 365 天有效期都已结束)→ CertPathValidatorException: validity check failed(原因 EXPIRED,出问题的证书在链中的下标 1)
  X509Certificate.checkValidity() 对正常叶子:通过
  X509Certificate.checkValidity() 对过期叶子 → CertificateExpiredException: NotAfter: Tue Sep 08 18:49:20 CST 2026

pathlen、keyUsage、basicConstraints

实测 · 本机执行输出
  pathlen:0 的中间证书下面又挂了一层子 CA [leaf2, ica2, ica],信任 root → CertPathValidatorException: basic constraints check failed: pathLenConstraint violated - this cert must be the last cert in the certification path(原因 PATH_TOO_LONG,出问题的证书在链中的下标 1)
  中间证书的 keyUsage 只有 digitalSignature(没有 keyCertSign)[leaf3, noku_ica] → CertPathValidatorException: CA key usage check failed: keyCertSign bit is not set(原因 INVALID_KEY_USAGE,出问题的证书在链中的下标 1)
  中间证书的 basicConstraints 是 CA:false [leaf4, notca] → CertPathValidatorException: basic constraints check failed: this is not a CA certificate(原因 NOT_CA_CERT,出问题的证书在链中的下标 1)
  ica 的 basicConstraints pathLen = 0,keyUsage keyCertSign = true

撤销检查

实测 · 本机执行输出
  撤销检查 开启(默认 true),没有 CRL 与 OCSP 可用,链 [leaf, ica] → CertPathValidatorException: Could not determine revocation status(原因 UNDETERMINED_REVOCATION_STATUS,出问题的证书在链中的下标 1)
  SOFT_FAIL → CertPathValidatorException: Certificate does not specify OCSP responder ← CertPathValidatorException: Certificate does not specify OCSP responder
  ONLY_END_ENTITY + SOFT_FAIL → CertPathValidatorException: Certificate does not specify OCSP responder ← CertPathValidatorException: Certificate does not specify OCSP responder
  不检查撤销时,验证 [leaf, ica] 这条链 2000 次:每次 835 μs(含读 PEM 文件与解析,不是纯验证)

分步演示

PKIX 路径验证
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12 的 CertPathValidator;证书由 keytool 在本机生成(EC secp256r1)
    • 没有验证:CRL 与 OCSP 的真实取回与 OCSP stapling、名称约束(nameConstraints)、策略映射、交叉证书、CertPathBuilder 自动补全中间证书(AIA)、主机名校验(属于 TLS 层,见前面的篇目)、SOFT_FAIL 在网络失败时的放行行为(这里没有网络失败的场景)
    京ICP备2026067502号-1京公网安备11010502063487号