我有一种情况,我的用户可以通过我的应用程序信任的第三方颁发的客户端证书对系统进行身份验证。颁发客户端证书的第三方提供了根证书和中间证书,这些证书已添加到服务器端的信任库中。现在,我需要验证我的客户端证书构建信任链,还需要检查客户端证书的OCSP状态。因此,我从我的托拉斯中加载了受信任的中间证书和根证书,并构建了证书路径,如下面的代码所示,这些步骤如下:
private KeyStore loadKeyStore() throws KeyStoreException {
KeyStore trustAnchor = KeyStore.getInstance(KeyStore.getDefaultType());
try (InputStream in = new FileInputStream(trustStorePath)) {
trustAnchor.load(in, trustStorePass.toCharArray());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return trustAnchor;
}
private PKIXCertPathBuilderResult buildCertPath(List<X509Certificate> certChain) throws KeyStoreException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, CertPathBuilderException {
KeyStore trustAnchor = loadKeyStore();
X509CertSelector certSelector = new X509CertSelector();
certSelector.setCertificate(certChain.get(0));
PKIXBuilderParameters params = new PKIXBuilderParameters(trustAnchor,certSelector);
CertStoreParameters intermediateCerts = new CollectionCertStoreParameters(certChain);
params.addCertStore(CertStore.getInstance("Collection", intermediateCerts));
params.setRevocationEnabled(false);
CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
PKIXCertPathBuilderResult builderResult = (PKIXCertPathBuilderResult) builder.build(params);
return builderResult;
}
这里certChain是我通过以下行从传入请求获得的证书数组,并将其作为列表传递给buildCertPath。
X509Certificate[] certArray = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
我有点困惑。看起来在此示例中,信任锚是根据通过请求的证书而不是从truststore加载的证书构建的。另外,在进行OCSP状态检查时,我计划从密钥库中获取我的颁发者证书,并将其传递给以下方法
public RevocationStatus validateOCSPStatus(X509Certificate cert, X509Certificate issuerCert) throws OCSPVerifierException, OCSPException, IOException {
LOGGER.info("Starting to validate OCSP status: ");
OCSPReq ocspReq = generateRequest(issuerCert, cert.getSerialNumber());
if (ocspReq == null) throw new OCSPVerifierException(ExceptionEnum.OCSP_Request_Build_Error);
RevocationStatus status = null;
URL url = getOCSPURL(cert);
if (url == null) throw new OCSPVerifierException(ExceptionEnum.OCSP_INVALID_URL_ERROR);
SingleResp[] responses = null;
OCSPResp ocspResp = getOCSPResponse(url, ocspReq);
if (OCSPResponseStatus.SUCCESSFUL == ocspResp.getStatus()) {
BasicOCSPResp basicResponse = (BasicOCSPResp) ocspResp.getResponseObject();
responses = (basicResponse == null) ? null : basicResponse.getResponses();
}
if (responses != null && responses.length == 1) {
SingleResp resp = responses[0];
status = getRevocationStatus(resp);
}
return status;
}
但是我从回购示例中了解到的信息令人误解,我可能需要从请求而不是从信任库中获取issuerCert(中间,根证书)。虽然我意识到如果证书有效,则我颁发的客户证书的中间证书和根证书应与我也加载到我的信任库中的第三部分证书颁发机构提供的证书相同,但是如果我的客户证书链还可以,那该怎么办它不是服务器信任的-因此,我想我必须从密钥库中构建我的trustanchor,而不是从请求中构建,并且在OCSP状态检查方法中,应该从密钥库中加载颁发者证书,而不是从客户端获取的请求还是我错了?
现在我有三个问题:
1)在buildCertPath方法中,信任库锚应该由通过请求或从信任库加载的证书(证书本身/中间/根)构建吗?
2)在buildCertPath方法中,是否应该从请求或信任库中获取中间证书?
3)最后,在方法validateOCSPStatus中,应从何处获得颁发者证书?换句话说,颁发者证书应该是什么-信任库中或请求中的证书?
我真的迷失在许多例子中,如果有人帮助我澄清问题,我将非常感激
答案 0 :(得分:1)
如果您使用的是Spring Boot,则应启用clientAuth
并让JVM负责客户端身份验证和CRL / OCSP检查,而无需手动检查所有检查。由于客户端证书是由第三方颁发的,因此可以通过将其添加到cacerts
或使用您自己的信任库和如下配置来确保它们是服务器JVM信任库的一部分:
-Djavax.net.ssl.trustStore="trust-store.jks"
-Djavax.net.ssl.trustStorePassword="a-great-password"
我相信OCSP检查默认是禁用的,您可以通过以下方式启用它:
System.setProperty('com.sun.net.ssl.checkRevocation', 'true')
Security.setProperty('ocsp.enable', 'true')
关于证书,假设您拥有Root -> intermediate CA -> client
之类的东西,如果您信任intermediate CA
,则客户只需提供其client
证书。如果仅包含Root
,则他们需要提供intermediate CA
和client
证书。