Java签名验证中如何获取证书吊销时间且不中断验证流程
解决方案:利用PKIX吊销检查器的软失败模式实现无中断验证并获取吊销日期
我之前在做证书链验证的需求时,刚好碰到过和你一样的问题——默认的CertPathValidator碰到吊销证书就直接抛异常中断流程,根本没法拿到吊销日期做对比。后来摸索出了利用PKIX吊销检查器的**软失败(Soft Fail)**模式来实现需求,下面是具体的实现思路和代码:
核心思路
Java的PKIX验证框架允许我们自定义吊销检查的行为,通过给PKIXRevocationChecker设置SOFT_FAIL选项,验证过程不会因为遇到吊销证书或无法获取吊销信息而抛出异常,而是会把所有证书的吊销状态收集起来,供我们后续处理。
具体实现步骤
1. 初始化PKIX验证参数并配置吊销检查器
首先我们需要初始化信任库和PKIX参数,然后获取默认的吊销检查器并修改其行为:
// 加载你的信任库(示例代码,实际需根据你的场景调整) KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); try (InputStream is = new FileInputStream("truststore.jks")) { trustStore.load(is, "password".toCharArray()); } // 初始化PKIX参数 PKIXParameters params = new PKIXParameters(trustStore); params.setRevocationEnabled(true); // 必须启用吊销检查,否则不会执行吊销验证 // 获取默认的PKIX吊销检查器 PKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) params.getRevocationChecker(); // 设置SOFT_FAIL选项:遇到吊销证书或无法获取CRL/OCSP时不抛出异常,继续验证 revocationChecker.setOptions(EnumSet.of(PKIXRevocationChecker.Option.SOFT_FAIL)); // 将修改后的检查器放回参数中 params.setRevocationChecker(revocationChecker);
2. 执行证书链验证
接下来调用CertPathValidator执行验证,此时即使链中有吊销证书,也不会抛出异常:
CertPathValidator validator = CertPathValidator.getInstance("PKIX"); // 这里的certPath是你要验证的证书链 PKIXCertPathValidatorResult validationResult = (PKIXCertPathValidatorResult) validator.validate(certPath, params);
3. 提取吊销信息并对比签名时间
验证完成后,我们可以从吊销检查器中获取所有证书的吊销状态,筛选出已吊销的证书并拿到吊销日期,再和签名时间对比:
// 获取所有证书的吊销结果 Map<X509Certificate, PKIXRevocationChecker.RevocationStatus> revocationResults = revocationChecker.getRevocationResults(); // 遍历结果,处理已吊销的证书 for (Map.Entry<X509Certificate, PKIXRevocationChecker.RevocationStatus> entry : revocationResults.entrySet()) { X509Certificate cert = entry.getKey(); PKIXRevocationChecker.RevocationStatus status = entry.getValue(); if (status instanceof PKIXRevocationChecker.RevokedStatus) { // 证书已被吊销,提取吊销日期 PKIXRevocationChecker.RevokedStatus revokedStatus = (PKIXRevocationChecker.RevokedStatus) status; Date revocationDate = revokedStatus.getRevocationDate(); // 这里替换成你的签名时间获取逻辑(比如从CMS/JWS签名中提取) Date signingTime = getSigningTimeFromSignature(); // 对比吊销日期和签名时间 if (revocationDate.before(signingTime)) { System.out.printf("证书 %s 在签名时未被吊销(吊销日期:%s,签名日期:%s)%n", cert.getSubjectDN(), revocationDate, signingTime); } else { System.out.printf("证书 %s 在签名时已被吊销(吊销日期:%s,签名日期:%s)%n", cert.getSubjectDN(), revocationDate, signingTime); } } else if (status instanceof PKIXRevocationChecker.UnknownStatus) { // 无法获取该证书的吊销状态(比如CRL/OCSP服务不可达) System.out.printf("无法确定证书 %s 的吊销状态%n", cert.getSubjectDN()); } // 若为ValidityStatus,则证书未被吊销,无需处理 }
注意事项
- Java版本要求:
PKIXRevocationChecker是Java 7及以上版本才有的API,确保你的项目使用的Java版本符合要求。 - 签名时间获取:签名时间需要从你的签名数据中提取,比如CMS签名可以从
SignerInfo的signingTime属性获取,JWS签名可以从header的iat字段获取。 - 时区问题:对比日期时要确保吊销日期和签名时间使用的是同一时区(建议统一使用UTC),避免出现时间对比错误。
- OCSP/CRL支持:默认的吊销检查器会自动处理CRL和OCSP两种吊销方式,如果你需要指定仅使用某一种,可以通过调整检查器的参数实现。
内容的提问来源于stack exchange,提问作者Lucas Grijander
相关产品推荐
相关产品推荐

