I wrote some code in Java to do this based on sample code on the Web. Essentially I used a Certficate Path Builder which would both locate a path based on a bucket of certificates and set of trust anchors (trusted certificates) and validate the path (including checking the revocation status).
Set<TrustAnchor> trustAnchors = buildAnchors();
X509CertSelector selector = new X509CertSelector();
selector.setCertificate(certificate);
PKIXBuilderParameters params = new PKIXBuilderParameters(
trustAnchors, selector );
params.addCertStore(
makeAdditionlCertStore(
certificate,additionalCerts));
params.setDate(messageSigningDate);
//
// Enable OCSP lookup
//
Security.setProperty("ocsp.enable","true");
//
// Enable Certificate Revocation List Distribution
// Points (CRLDP) support
//
System.setProperty(
"com.sun.security.enableCRLDP","true");
CertPathBuilder builder =
CertPathBuilder.getInstance("PKIX");
return builder.build(params);
This seemed to be working fine. I tested this with a SSL path issued by a public CA and it was able to get the revocation status and all was well. I disabled OCSP and it still fetched the revocation status using a CRLDP extension in the certificate.
What I didn't initially check was that if I disabled CRLDP it failed even though the path I was testing had an AIA extension pointing at an OCSP server which was accessible. I did some Googling on this and found this which seems to indicate OCSP is not supported via the path builder before JDK 1.8!
So then I re-wrote the code to use the certificate path validator and again this didn't work but this time I got a wrong key usage exception. Well according to this there is a bug in 1.7 update 6 through 10 where OCSP fails with this error!
I updated to update 25 and sure enough the problem goes away.
The problem with the path validator is it literally does what the name implies and so unless you have a path already built for you then you either have to use the path builder or do it yourself. With PKCS#7 structures the ordering of the additional certificates is arbitrary (well they are ordered lexicographically on their encoding according to DER as they are sent as part of a SET) so you can't assume they will be in path order.
My solution in the end was to use the path builder to build the path but turn off revocation checking and then once I have a path to validate it with the path validator. This is going to be pretty inefficient but then what choice have I got until I can upgrade to 1.8?
public void validateCertificate(
X509Certificate certificate,
List<X509Certificate> additionalCerts )
{
Set<TrustAnchor> trustAnchors =
buildAnchors();
CertPath cp =
makeCertificatePath(
trustAnchors,
certificate,
additionalCerts,
messageSigningDate);
PKIXParameters params =
new PKIXParameters(trustAnchors);
params.setDate(messageSigningDate);
params.setRevocationEnabled(true);
params.setSigProvider("BC");
//
// Enable OCSP lookup
//
Security.setProperty("ocsp.enable","true");
//
// Enable Certificate Revocation List Distribution
// Points (CRLDP) support
//
System.setProperty(
"com.sun.security.enableCRLDP","true");
CertPathValidator cpv =
CertPathValidator.getInstance("PKIX");
return cpv.validate(cp, params);
}
private CertPath makeCertificatePath(
Set<TrustAnchor> trustAnchors,
X509Certificate certificate,
List<X509Certificate> additionalCerts,
Date messageSigningDate)
throws CertificateException,
InvalidAlgorithmParameterException,
NoSuchAlgorithmException,
CertPathBuilderException
{
X509CertSelector selector = new X509CertSelector();
selector.setCertificate(certificate);
PKIXBuilderParameters params = new
PKIXBuilderParameters(trustAnchors, selector );
params.addCertStore(
makeAdditionlCertStore(certificate,additionalCerts));
params.setDate(messageSigningDate);
params.setRevocationEnabled(false);
params.setSigProvider("BC");
//
// Throws if path building/validation fails
//
CertPathBuilder builder =
CertPathBuilder.getInstance("PKIX");
CertPathBuilderResult result =
CertPathBuilder.getInstance("PKIX");
CertPathBuilderResult result =
builder.build(params);
return result.getCertPath();
}
No comments:
Post a Comment