Reputation: 61
I have a case that my users can authenticate the system via client certificates issued by the 3rd party to whom my application trusts. The 3rd party who issues my client certificates provided root and intermediate certificates which I have added to my truststore on the server side. Now, I need to validate my client certificate building chain of trust and also checking OCSP status of the client certificate. So I loaded trusted intermediate and root certificates from my trustore and built cert path as the code below shows these steps:
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;
}
Here certChain is array of certs that I obtained from incoming request via the following line and passed it to buildCertPath as List.
X509Certificate[] certArray = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
Then I came accross this repo on the net https://github.com/nandosola/trantor-certificate-verifier/blob/master/src/main/java/cc/abstra/trantor/security/certificate/ocsp/OCSPVerifier.java
And I am kind of confused. It seems like in this example trust anchor is built from the cert coming through the request not the ones loaded from truststore. Also while doing OCSP status checking I was planning to get my issuer cert from keystore and pass it to the following method
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;
}
But what I understood from the repo example I am misleading and I might need to get issuerCert(intermediate, root certificates) from request not from my truststore. Though I realize that if certificate is valid, intermediate and root certs issued my client certificate should be the same as the ones provided by 3rd part certificate authority which I also loaded to my truststore, what if my client cert's chain is ok, but in fact it is not the one my server trusts - thus I presume I have to build my trustanchor from my keystore not from the request and also in the method for OCSP status checking issuer cert should be loaded from keystore not the request I am getting from the client or am I wrong?
Now I have three questions:
1) In the buildCertPath method should truststore anchor be built from the certs(cert itself/intermediate/root) coming through the request or loaded from the truststore?
2) In the buildCertPath method should intermediate certs be obtained from the request or truststore?
3)Finally, in the method validateOCSPStatus from where should I get issuer cert? Put it another way, what should be issuer cert - the ones in the truststore or in the request?
I am really lost among lots of examples out there and I'd be really grateful if anyone helps me clarify my questions
Upvotes: 0
Views: 1188
Reputation: 196
If you are using Spring Boot, you should enable clientAuth
and let the JVM take care of client authentication and CRL/OCSP checks without you manually checking all of that. Since the client certs are issued by a third party, make sure they are part of your server's JVM's trust store either by adding them to cacerts
or using your own trust store and a configuration like this:
-Djavax.net.ssl.trustStore="trust-store.jks"
-Djavax.net.ssl.trustStorePassword="a-great-password"
I believe OCSP checks are disabled by default and you can enable that with:
System.setProperty('com.sun.net.ssl.checkRevocation', 'true')
Security.setProperty('ocsp.enable', 'true')
About the certs, assuming you have something like Root -> intermediate CA -> client
, if you trust the intermediate CA
, the client needs to only offer their client
cert. If you only include Root
, they will need to offer intermediate CA
along with the client
certificate.
Upvotes: 1