How to disable common name check in SSLContext in java? - java

I am using SSLContext so set up Jersey client, and need to disable the common name check in order to avoid unnecessary issues. However, I can find no documentation as to how we can do it correctly. So is the common name check disabled by default in SSLContext (assuming using TLS) or do we need to explicitly disable it? If so, how? Thanks.

This does not answer your question, but it tells you that what you are doing is a bad idea and probably caused by a misunderstanding of how verification works.
...need to disable the common name check in order to avoid unnecessary issues
I don't know what the "unnecessary issues" are which you are trying to avoid, but not verifying the hostname is more or less that same as disabling all validation and thus make it possible to incorporate the server and/or to do man-in-the-middle attacks.
If you don't verify the hostname but still validate the certificate trust chain the attacker can now simply use a certificate signed by a trusted CA for the attackers own site, e.g. attacker.example.com. CA's will issue such certificate since the attacker can prove ownership of its own site.
Using its own certificate the attacker can now incorporate all the other sites, since the trust chain is valid even if the hostname is not. This is the same as if you would accept any kind of identification issued by a state, without even looking if the picture in the I.D. matches the person showing the I.D.

If I'm understanding you correctly, I think you can accomplish what you are trying to do by implementing a HostnameVerifier, and just returning true in the verify method. You can set up the verifier on the ClientBuilder. For example
Client client = ClientBuilder.newBuilder()
.sslContext(sslContext)
.hostnameVerifier(hostnameVerifier)
.build();

Related

SSL CA certificate in java

I have a question about the usage of ssl in java.
My need is quite simple, to connect to a server (https, ldaps, ...), using the CA certificate of the server (pem format)
When using api as curl or many other I guess, in C++ or command line, you can specify a single CA certificate (in pem format for instance) when performing a connection.
If I well searched (hum), in java (i mean with standard librararies) it's slightly different.
either you add your certificate into a trustore, having to manage it by external application as keytool (of course you could programmatically manage your trustore, but it's not my point)
[and additionally, you can specify a trustore with System property, but you can't specify a cert directly]
either you have to code a little, like overloading the SslContext or the TrustManager class, to enable to add a certificate "on the fly".
Am I missing a simpler way, like method "connection.setCA(String caCertPath)" ?
Thank you,
RE: "Am I missing a simpler way, like method "connection.setCA(String caCertPath)" ?"
I guess it depends on the java class you use to implement the application.
But as far as my knowledge goes the answer is: no. You indeed need to first store the certificate in a keystore to be consumed by the class you are using.
I am not aware of any class that would work the way you expect the certificates to be consumed, but I guess you could just write that class to sit on top of the class you don't like.

HostnameVerifier vs TrustManager?

Under what circumstances would one use a HostnameVerifier over a TrustManager in Java? Is one recommended over the other? Looking at the Java docs (Interface HostnameVerifier and Interface TrustManager), I can't tell when its best to use either (though the TrustManager seems more versatile).
In the past, I have always used a custom TrustManager. However, I noticed Heartbleed exploit in java uses both (but I don't think its correct).
EDIT: when using HostnameVerifier, are the other customary X509 checks performed, like path building and expiration and revocation (if configured)? I think I am essentially asking if HostnameVerifier supplements the other checks (rather than replacing them).
For example, suppose a dev server is at dev.example.com and its signed by an internal CA. There's one DNS name in dev.example.com's certificate, and its dev.example.com. Further, suppose I connect to it as 192.168.1.10. Could I use a HostnameVerifier to allow both dev.example.com and 192.168.1.10? In this scenario, is the additional name allowed and are the other customary X509 checks are performed?
Under what circumstances would one use a HostnameVerifier over a TrustManager in Java?
Never. They do different things. TrustManage authenticates certificates as part of SSL. HostnameVerifier verifies host names as part of HTTPS. They're not in competition.
Is one recommended over the other?
No.
EDIT
The TrustManager runs during the TLS handshake. If it indicates failure, the handshake is aborted and the connect fails.
The HostnameVerifier runs after the TLS handshake, over a TLS connection that is already valid from the TLS point of view, so at that point you know that the certificate is valid, signed by a trusted issuer, non-expired (?), etc., and all you have to do is decide (a) whether it's from the correct server and (b) whether you trust that server. You might do (b) inside a TrustManager, but far more commonly you wouldn't provide your own TrustManager at all.

Behavior of HttpURLConnection for URL with Revoked SSL Certificate?

We're going to have a bumper crop of revoked SSL certificates, courtesy of heartbleed. When I saw that Chrome on Android apparently ignores revoked SSL certificates, I wondered what the behavior would be when requesting in Java a Web resource from a server, where we get a revoked SSL certificate.
What I hoped for was a crash with some sort of SSLHandshakeException.
What I am seeing is a successful connection, but downloading no data -- reading from getInputStream() returns a length of -1. This is tested using https://revoked.grc.com/ as my test site, which will return an explanatory page if you download it ignoring certificate errors (e.g., via wget -no-check-certificate). I have tried 4.4, 4.3, and 2.3 emulators, with the same results.
Is there a specified behavior for the Java VM? I doubt that there is an Android-specific specification, but if Android's actual behavior differs from a Java specification, I can work to get the differences clarified as either being bugs or missing documentation.
The expected behavior would be for X509TrustManager to catch a CertPathValidatorException from CertPathValidator and re-throw it as a CertificateException (a CertificateRevokedException when available in Android).
CRL checking is disabled here, on line 362. Note that its not as easy as removing that line, since if a cert has no CRL, a CertPathValidatorException is also thrown.
CertPathValidator is implemented here and as far as I can tell, by wandering through the source, it doesn't download the CRL's.
This is based on a cursory reading of the javadocs and the JSSE Reference Guide for Java.
The javadoc does not say what happens in the way of SSL certificate verification. On the contrary, the APIs make it clear that the whole process is highly customizable, starting with a SSL socket factory and/or a HostnameVerifier. The javadocs do not say anything about the behaviour of the defaults.
The JSSE reference goes into a lot more detail, but it is also very complicated ... and clearly JSSE implementation specific. But I think it says that this stuff is handled by the trustmanager, and the default trustmanager is PXIX. Then it says the following:
"If the init(KeyStore ks) method is used, default PKIXParameters are used with the exception that revocation checking is disabled. It can be enabled by setting the system property com.sun.net.ssl.checkRevocation to true. Note that this setting requires that the CertPath implementation can locate revocation information by itself. The PKIX implementation in the SUN provider can do this in many cases but requires that the system property com.sun.security.enableCRLDP be set to true."
In short, certificate revocation checking is disabled by default.
I haven't researched the Android case, and I would not expect the Android implementation to be the same.

Validate Extended Validation(EV) of SSL certificate using JSSE

I got list of URLs, and I want to validate their Extended Validation (EV) attribute using JAVA
I can make request and get their certificate, but I am not sure how to validate “Extended Validation” for a given site.
Is there any special value in certificate? Or any attribute?
Extended validation is mostly useful from a user-interface perspective. It's not so useful if your client doesn't have anything in its user interface to display the certificate. These verifications are not integrated by default in the JSSE, possibly because there is little demand for it (lack of Java browsers). (By the way, you should verify the certificate you get upon connection, not check with a first connection and connect with another, just in case).
The specifications are defined by the CA/browser forum.
The OID values and root CA certificate fingerprints are hard-coded into browsers (see security/certverifier/ExtendedValidation.cpp in Firefox, used to be in in security/manager/ssl/src/nsIdentityChecking.cpp). There is also a list on Wikipedia for reference, although in principle you should check the policy OIDs with each CA.
To analyse the extensions, it might be useful to use BouncyCastle if X509Certificate.getExtensionValue() isn't enough.
One problem you will have to watch out for is that the hard-coded SHA-1 fingerprints of the root CA certificates need to match exactly those certificates in the trust store. Some CAs renew their CA certificates once in a while in the bundles that are shipped with most browsers/OS/JREs: make sure you're using the same.

Programmatically adding a trusted cert in Java

I use SSL to communicate between two components written in Java. I can't use a CA, so I have to self-sign everything. Unfortunately, this means that when I try to handshake, I get a SunCertPathBuilderException. I can create my own X509TrustManager that just trusts everything, but that sort of defeats the purpose of having a signed cert.
I would like, when first making the connection, to prompt the user with "SSL handshake with invalid cert. Add cert to store?" or something so they could have it added for them to their certificate store, like web browsers do at sites with invalid certs. I can find plenty of examples online of adding a cert to the store through the commandline, but I can't figure out how to do it programmatically. Is there a way to do this?
Yes it is possible.
There is some code here that I've used before. I had to modify it to do what I wanted and I suspect that you will too but this should get you close - you aren't trying to import a key so theoretically you should be able to simplify things. In any case you can get an idea of what you'll need.
The JDK JavaDoc for java.security.KeyStore is pretty useful too.
Why don't you create your own CA and sign your certificates with that? Then all you would need to do is install the CA own certificate on the machines and every certificate signed by that CA would validate.
Why would you need to do this, you are not validating that the client is who they say they are you are only using the certs to encrypt the comms, so a custom trust manager that allows all certs is all you need.
What you are asking is possible and from memory also involves a custom trust manager to validate the certificates and store them in the keystore. I can't remember the details, but at least you know it is possible to do it.

Categories

Resources