I have a web app that requires a client to send it's certificate and the server has to validate the certificate(i.e see if the issuer is a valid issuer and present in the server's truststore). Here is the code :
FileInputStream fin=new FileInputStream("C:/trustedca");
KeyStore anchors = KeyStore.getInstance("JKS","SUN");
anchors.load(fin, "server".toCharArray());
X509CertSelector target = new X509CertSelector();
FileInputStream fin1=new FileInputStream("C:/client.crt");
CertificateFactory cf=CertificateFactory.getInstance("X.509");
X509Certificate cert=null;
while (fin1.available() > 0)
{
System.out.println("in while---------");
cert =(X509Certificate) cf.generateCertificate(fin1);
}
target.setCertificate(cert);
PKIXBuilderParameters params = new PKIXBuilderParameters(anchors, target);
CertPathBuilder builder = (CertPathBuilder) CertPathBuilder.getInstance("PKIX").build(params);
PKIXCertPathBuilderResult r = (PKIXCertPathBuilderResult) builder.build((CertPathParameters)params);<br>
But I get an exception :
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid
certification path to requested target<br>
NOTE :
Here the certificate sent by the client is client.crt and the cerificate used to sign the client.crt certificate is the ca.crt which is present in the keystore "trustedca". Then why is it giving this exception?
If you're expecting a client certificate, let the JSSE do all of this for you. If you want to use your own trust store for a particular connection, configure the JSSE to use it. Check the Customizing JSSE section in the reference documentation.
Here is a short example for building an
SSLContext
with a custom trust store. (Other, more complexX509TrustManager
s can also be used, but you rarely need that.)If you're using an existing application server, how to pass configure all this will depend on the server and how it expects to be configured. Using the JSSE for this will also make sure that the key usage attributes are appropriate.
If you get the certificate via some other means and want to validate it, you need to use the PKI API. If you follow the Example of Validating a Certification Path using the PKIX algorithm, you should get to something like this:
Check the result from validate (and that it hasn't thrown a validation exception, of course). Here, I've disabled revocation checks to simplify. You can also set other aspects of the
PKIXParameters
for policy checks. This can get quite complex (and why it's better to let the default JSSE managers do that for you).You were also asking about all this in the context of this other question you asked on Security.SE: What is the actual value of a certificate fingerprint?.
Suppose you have two
X509Certificate
s:serverCert
andcaCert
, where you want to verify thatserverCert
was signed by (the private key matching the public key in)caCert
.The simplest way:
If you want to do this a bit more manually, use the
Signature
API:Assuming the algorithm is
SHA1withRSA
, you could also compute the digest:The digest itself will only be part of the result from using
Cipher
: what you get fromserverCert.getSignature()
is in fact a more complex ASN.1 structure, which includes the digest algorithm identifier, in this case, thedigestBytes
should be prefixed with something like this:(BouncyCastle may be useful if you want to analyse the ASN.1 structure properly.)
Note that none of this verifies the time validity or any other attributes. PKIX compliance is far more than checking the signature (see RFC 3820 and 5820).
Maybe a valid path can't be constructed because some intermediate certificates are missing. Your loop to load certificates discards all but the last. Instead, save all of those certificates, and pass them to the
CertPathBuilder
to aid in path construction.Another common problem is that revocation checks are performed by default, which is good for security. If you don't understand how to obtain a CRL, or utilize OCSP, you can diminish your security and disable revocation checks. This is also shown in the example below.
It would help to know how you are obtaining the "client.crt" file and what its contents are expected to be. Like the responders, I wonder why you can't use the built-in facilities of JSSE to perform this validation.
JSSE already does all that. You don't have to do any of this, except maybe verify that the peer certificate hasn't expired.