I have an instance of X509Certificate in java and I need to check if the issuer is trusted?
thanks
gal
If you just have the certificate (out of context), you should build a certification path using the Java PKI Cert. Path API. If it's within the context of SSL, you should be able to use a TrustManager and check it when using your SSLContext.
This will verify whether the certificate was issued by a CA you trust (or via one of its intermediate CAs perhaps).
You may also be interested in "What data should I validate when validating X.509 certificates using Java?" (on Security.SE).
Related
UPDATE: After I have found a solution, I edited the question to be more clear for future reference.
I've got a corporate (ie not well known) CA certificate from a company which provides us a web services to be called from Java. I added this CA certificate to default cacerts trust store (keytool -import -file cert.cer -alias myca -keystore jre/lib/security/cacerts), but connection to the service still fails with the dreaded "PKIX path building failed" message. I have checked that issuer field of the end server certificate is the same as in the CA certificate and also validity dates is ok.
I don't know how to explain this. I can think of the following reasons but I don't know which one is true:
I have noticed that when I add also the end server certificate to trust store, the connection is OK. Maybe cacerts by design don't work as I expect (ie all the certificates signed by an authority added there are considered valid), but instead I have to add all the end server certificates to a trust store including CA certificate of their issuer.
I have to add CA certificate in some other way - by different command, to different file etc.
Maybe the CA certificate is not correct and keytool refuses to consider it a certificate authority.
Maybe PKIX path building fails for other reason.
How can I debug this problem more to find an answer?
Details:
The end server certificate is wildcard certificate
There is no intermediate certificate, just root and the end certificate
I was facing the same problem with "PKIX path building failed" with Let's Encrypt signed certificates at a time Java didn't incorporate the Let's encrypt CA certificate in its default trust store.
My story is written in detail here: http://blog.novoj.net/2016/02/29/how-to-make-apache-httpclient-trust-lets-encrypt-certificate-authority/
At the end I was able to make Java trust "the end of the chain" server certificate by creating internal trust store embedded in my application that contains only root CA certificate (and the backup one).
I much more prefer creating internal application truststore than importing certificate in main Java trust store for two reasons:
you don't need another extra step in install procedure for initializing the global trust store
you limit "the trust" to you application and don't affect another applications running on the same JVM (or better you can even limit the trust to the certain instances of client objects in your application if required)
Maybe I had a different scenario than you're facing, so downvote me if I didn't get the point.
The trust store needs to contain the root certificate (the CA's cert).
I'm not sure if that's what you mean by "the last one I'm the chain", but the CA certificate should be the last one in the certificate chain presented by the server.
If your certificate is signed by a well-known CA, then the CA cert should be in the trust store, and if the server's certificate chain is set up properly, everything should just work.
If yours is a self-signed certificate, then the root certificate will not be in the trust store, and you will have to add it.
Thanks to #pedrofb comment I found out that the reason PKIX path fails is simply that the CA certificate I got is not the CA that signed the end certificate. What made it so complicated is the monstrous incompetence of company that gave me the CA certificate which obviously has two CAs with almost the same description (cn, o, st, c) which differs only in SN and which both issued the same wildcard certificate. Only after I became super paranoid and compared the SNs, I understood the problem.
I am writing a micro service which talks to another service through HTTPS. In java client implementation, reading root certificate from truststore and then validate incoming certificate through that.
Now, my question is - by default only 2nd level certificate will be validated using root Cert or all chained certificates in turn will also get validated?
I am Using okhttp; and my assumption is that all Java clients should behave in same way, please let me know if there is any subjectivity here? Thanks.
If you include the root certificate in the truststore, the entire chain will be validated
The SSL server during handshake sends to client the certification chain from leaf certificate to root. The root certificate may be included but usually it is not
The default Trust Manager of a Java client will validate the provided certification chain looking in the truststore until it find the issuer of the certificate or the certificate itself
I'm having an issue sending our certificate (client) to another server during a web service call.
We're expected to return the certificate with the CN:
b2b-test
however whenever we receive the servers certificate and attempt to send our own, we're getting:
Unable to find valid certificate path to requested target
From my understanding, if I put our certificate b2b-test inside of our keystore jre/lib/security/cacerts, then when receiving the server request, it should send the appropriate certificate.
How does the client know which key from the keystore it should send to the server? Should I be specifying the exact certificate to send during my request, or is it enough for it to be in the keystore?
Currently the server is sending back the certificate
b2b-a
The certificate chain shows:
*** Certificate chain
chain [0] = [
[
Version: V3
Subject: CN=b2b-a, OU=Web Technologies
The URL for the service is:
https://b2b-a/service
If I configure it like one way ssl, and put the servers certificate into our cacerts, then it picks up their cert and fails the handshake (I'm assuming because it's expecting our cert and not theirs back due to it being a two way setup).
I'm a little stumped here. Any clarification on what I've said is greatly appreciated.
The "Unable to find valid certificate path to requested target" error usually occurs when one side passes a certificate for which the other side doesn't trust any of the certs in the chain. You'll generally (always?) see the error message on the side that's receiving the cert (the side that's missing the truststore).
If you're the client and they're the server, one-way SSL would send their cert from them to you and you would validate it (making sure that the hostname matches the content in the cert), but it would not send any cert from you to them nor would they do any validation.
You'll want to make sure you're configuring a truststore that contains either the b2b-a certificate or a certificate that was used to sign it (but that cert doesn't appear to have any root CAs, so you're stuck with directly importing the cert itself). So yes, you want to do what you wrote in your post and put their certificate into your cacerts. And you'll also need to make sure that the b2b-a service trusts the cert you're sending (or a root CA that was used to sign your cert, if any), so you'll need to put your cert into their cacerts as well, or do something equivalent.
Note that putting a cert in cacerts (or in a truststore JKS) DOES NOT send any certs to anyone; any truststore is used only to allow you to validate that you trust the certificate someone else provides you, either because you trust the cert or because you trust a CA cert that was used to sign the cert. No certs are picked out of the cacerts directory to send to another machine.
If you're using a JKS rather than the JRE directory (which is generally a better idea, since you can specify a different set of trusted certs for your process without changing the default set for anyone running a Java project within your JRE), it's possible to use the same JKS as both a keystore and a truststore (you'll just provide the same filename and password for both the keystore and the truststore properties), or you can have two separate files; either approach will work.
From my understanding, if I put our certificate b2b-test inside of our keystore jre/lib/security/cacerts, then when receiving the server request, it should send the appropriate certificate.
Certainly not. That's a truststore. A source of trusted certificates. Don't mess with it. It isn't used for the purpose you require and in any case it is updated every Java dot release, which clobbers your changes.
Your own certificate and private/public key pair should go in a file of your own, a keystore, which is defined to JSSE by the javax.net.ssl.keyStore and javax.net.ssl.keyStorePassword system properties, or by more complex means described in the JSSE Reference Guide.
The keystore is a precious and confidential file containing your private key. Guard and protect it. Private key leakage would compromise your security and identity.
I need some help ensuring that our PKI infrastructure is secure. This is how it works:
We have one (self-signed) CA cert that our server has full control over.
All clients (written in Java) are configured with a trust-store that only contains this CA-cert.
During installation of a client the server issues a client certificate (with it's client-id as CN) that is signed by our CA cert.
The clients are then able to connect to each other and when the connection is established a mutual client authentication is performed by validating the clients' respective cert. We initialize the TrustManager that handles the clients' authentication like this:
.
private TrustManager[] getClientCATrustManagers() throws NoSuchAlgorithmException, IOException, KeyStoreException, CertificateException {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
KeyStore trustStore = getClientCATrustStore();
trustManagerFactory.init(trustStore);
return trustManagerFactory.getTrustManagers();
}
getClientCATrustStore() returns the trust-store that only contains our CA.
This leads me to my question. My understanding of chain validation is that as long as the root of the chain is trusted and none of the certs along the chain have expired the chain is considered valid. What concerns me about this is that I then see the risk that the client will be able to use it's own cert to issue new certs. Is that a potential risk and if so, how do I prevent it? I see the two potential solutions:
I create my own TrustManager that prevents this. Are there any implementations that already does this?
When the client cert is issued by the server I somehow specify that the client cert is not allowed to issue it's own certs. Is this possible and if so, how?
You are correct about a certificate chain being valid and trusted if the root is trusted, and all the intermediate certs are present and valid.
And you are also correct about the potential risk of a client issuing another cert under their own. But there are ways to mitigate this risk.
X509 certificates (version 3) contain extensions that indicate what they are allowed to do or not do.
For example there are 2 specific sections that you would probably be interested in:
Basic Constraints
Key Usage
The Basic Constraints identifies if the certificate is a CA or not, which means it can only be used to verify a certificate signature if it is designated as a CA itself. It also specifies a path length. This limits the number of CA intermediate certs this CA can sign/issue. A good explanation of this path length is in this SO question. It sounds like you would want a path length of 0 on the CA certificate.
Key Usage indicates what this entity is allowed to do. Typically, CA certs have the following key usage attributes: Certificate Signing, CRL Signing. Whereas non-CA or "End entity" certificates can have: Digital Signature, Non-Repudiation, Key Encipherment, Data Encipherment.
These extensions are all governed by RFC5280.
And here is the important part. For these certificate extensions to mean anything, they have to be checked and enforced by the application using them.
Your client app can look at the extensions and verify that the path length of the other client's cert is 0 (meaning there are no intermediate certs between the CA and the client cert).
I have 1) X509 Certificate (child) -> Authentication CA (parent) certificate and -> root CA (root) certificate.
Questions:
Can I retrieve this Authentication CA certificate from current X509Certificate certificate?
when I double click my certificate, I see the hierarchy of certificates. And from here, I can open each one. So, can I get Authentication CA certificate location or something like that from that certificate?
what ways can you recommend , in order to retrieve Authentication CA certificate?
I need to do this using java code. not key tool or something like that. I have Root CA certificate and X509 Certificate (child). and I need parent of child certificate.
I use bouncycastle and java's classes in order to work with certificates.
An X.509 certificate does not contain within it the certificate of the issuing CA. If you double-click on the child certificate and see a chain, this suggests that your operating system has access to the intermediate certificates (somehow).
If you need a chain of certificates, then you need to retrieve this from some external source. Many protocols (such as SSL) will provide a full certificate chain by default. The answer really depends upon the context of your problem, which is not clear from your question.