Java 是否检查信任库的过期日期?

问题描述 投票:0回答:1

Java 11 sun.security.ssl.SSLSocketImpl#startHandshake 实现是否检查信任库的过期日期? 这意味着,如果信任库过期,SSL 握手将会失败,因为它没有经过 Java 验证?

提前感谢您的帮助! 最好的问候

java ssl truststore
1个回答
2
投票

TLDR:

Java 实现 RFC 5280 中为 PKIX 指定的证书链(或正式的 path)验证,该验证根据每个证书的有效期(notBefore 和 notAfter=过期)检查当前(或指定)时间,从叶到但不包括“锚”。事实上5280甚至不要求主播“有”证书或者“有”有效期;请参阅第 6.1.1 节,并观察有效性不在锚点设置的初始参数(大部分)之中。 这有点模糊,因为 Java 通常“以自签名 [即根 CA] 证书的形式提供信任锚......”,正如该部分所说“可以”完成。通常的默认信任库

file

、JRE/lib/security/cacerts(或 JSSE=SSL/TLS jssecacerts,如果存在)确实包含根证书,许多(如果不是所有)其他系统和库使用的信任库也是如此。使用 X.509/PKIX 证书(至少 Windows、MacOS、OpenSSL、NSS 和 GnuPG 的 SMIME 部分)。如果您使用 JSSE 的默认值 TrustManager,它总是使用该类型的文件,尽管您可以指定不同的文件名,并且如果您使用 JSSE 的默认值 TrustManager

implementations
TrustManagerFactory
获得,它们会通过采取一个更高的级别KeyStore 包含/提供根证书的对象——您可以使用文件以外的其他内容创建该证书。
当 JSSE 需要验证握手的证书链时,SSLSocketImpl(或 SSLEngineImpl)不会直接执行此操作,而是调用从工厂和上下文(默认或其他)设置的 TrustManager,并且首先
上述默认值
调用

checkTrustedInit

,它(一次)调用 sun.security.validator.Validator.getInstance 来创建

SimpleValidator
PKIXValidator,然后用于验证证书链。前者(现在被认为已过时,但仍在代码中)直接实现了验证算法的更简单/早期版本,正如您在 chain[chain.length-1] 处看到的锚/根,它在将其变成 之前几乎不进行任何检查sun.security.cert.TrustAnchor
 用于检查较低的证书。后者(现在默认)更复杂,并且使用 CertPathValidator
(可能还有 
CertPathBuilder
)API,最终会做同样的事情。
如果您愿意,您可以替换自己的 
TrustManager
实现,该实现以不同的方式实现标准(可能包括检查锚定证书的有效期),甚至根本不实现(在这种情况下,您建立的连接的安全性当然取决于您的内容)实施)。

Let's Encrypt 实际上(更新:)直到 2024 年都使用这样的行为来

支持旧版本的 Android
,这些版本没有 LE 自己的根证书“ISRG Root X1”,因为它们早于 2015 年左右,并且不能更新通常是因为制造商停止支持它们甚至停止存在。虽然他们仅针对 Android 描述了这一点,但它实际上也适用于 Java——在 Java 中不需要它,因为 Java 的大多数用途(可能除了嵌入式/卡版本 ME)都可以更新,或者至少可以维护信任库。

更新:

从 2024 年春季开始,LetsEncrypt(最终)放弃使用 DST-X3,因此现在要做下面的演示,您必须创建自己的使用旧链的服务器——并且在 2024 年 9 月 30 日之后当 bridge 证书过期时,您还必须使用错误设置或伪造的时钟让客户认为它是在该日期之前。虽然技术上可行,但这不再简单。 您(更新:)可以通过运行以下代码来读取过期的 DST-X3 根证书并仅使用它来演示这一点,而不是人们通常应该使用的 ISRG-X1 根,以验证与以下站点的连接使用具有“兼容性”链的 LetsEncrypt 证书——StackExchange 本身(包括 stackoverflow.com)至少目前就是这样一个站点。您无法从当前的 Java 获取 DST-X3,它已被删除,因为它已过期并且不应该使用(当然删除它确实会导致使用它的证书链验证失败!)或大多数其他系统/设备(如果当前)。如果您使用早于去年秋天的

Oracle

Java 包,它确实具有 DST-X3 证书;如果您使用较旧的 OpenJDK,它可能使用确实具有 DST-X3 的私有 cacerts,但根据您使用的构建器的包,它可能会使用更新为删除 DST-X3 的外部(平台)信任库,即使 Java 本身也如此没有更新。您还可以直接从 LetsEncrypt 或 Identrust 或从公共存储库(如 this one)(也由 LetsEncrypt 链接)获取 DST-X3。 // file_containing_CAcert(e.g. DSTX3) hostname [port] X509Certificate c; try( InputStream is = new FileInputStream (args[0])) { c = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is); } System.out.println (c.getNotAfter()+" "+c.getSubjectDN()); KeyStore ks = KeyStore.getInstance("PKCS12"); // any file-based ks.load(null); ks.setCertificateEntry("test", c); TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); tmf.init(ks); SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(null, tmf.getTrustManagers(), null); SSLSocket s = (SSLSocket) ctx.getSocketFactory().createSocket(args[1], args.length>2? Integer.parseInt(args[2]): 443); s.startHandshake(); System.out.println ("successful!"); for( java.security.cert.Certificate t : s.getSession().getPeerCertificates() ){ X509Certificate x = (X509Certificate) t; System.out.println (x.getNotAfter() + " " + x.getSubjectDN() ); }

© www.soinside.com 2019 - 2024. All rights reserved.