1

I'm building an application that needs to open self-signed HTTPS SSL URLs in java. I've learned that you can bypass the SSL problems by adding a call to HttpsURLConnection.setDefaultHostnameVerifier() where you say what hostnames are allowed.

However, I have a second problem where my servers are running self-signed certs. So even with the hostname bypass I'm getting exceptions like:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

I've looked around and the only solutions I've found is to add the certificate to the java key store, but this is a problem for me because I have no control over when or how they update java, and I've read that the keystore isn't preserved between updates, and I have no access to the system outside of the JVM.

My application will only make calls to a single server so if there was a way to bypass the self-signed restrictions, and never consult keystores, it wouldn't be a security problem, but is there a way to do this?

rjcarr
  • 2,072
  • 2
  • 22
  • 35

4 Answers4

2

I'm building an application that needs to open self-signed HTTPS SSL URLs in java. I've learned that you can bypass the SSL problems by adding a call to HttpsURLConnection.setDefaultHostnameVerifier() where you say what hostnames are allowed.

There are some misconceptions from your question:
Hostname verification is unrelated to whether the certificate is self-signed or not.
It is a verification that matches the domain you are trying to access with the certificate info (CN or Subject Alt Name).

You would need to configure the verifier if you needed to accept a certificate that did not match the url (not recommended at all!!!)

Concerning the self-signed.
This is irrelevant.
You can configure your application to load your custom truststore which would include the certificate your application will trust. In fact this is the best approach (than using Java's cacerts).
All you have to do is import the certificate in a keystore (JKS or PKCS12) and load it in your custom TrustManagers in your application.
Just google arround, plenty of examples E.g. self-signed-ssl

Community
  • 1
  • 1
Cratylus
  • 52,998
  • 69
  • 209
  • 339
  • Thanks for the response, I should clarify. I mean if I go to a valid SSL site with a correctly signed cert, I still needed to add the verifier before it would work. My example was https://gmail.com, so maybe that was special. It sounds like you're saying I can update my trust stores while in java and just do it irrespective of a java update. I'll look into this further, thanks! – rjcarr Jan 28 '12 at 21:25
  • If you access this site via browser you get warning.Seems because they used `accounts.google.com` for CN and you typed `gmail.com`.In this case you would need a hostname verifier to be configured not to throw an exception.I highly recommend to NOT do that though if you have real security requirements – Cratylus Jan 28 '12 at 21:37
  • Thanks 384706, when you described it that's what I figured was happening. That makes sense now. The thing is, I really don't have a security requirement, they (my customers) just use SSL and self-signed certs for the encryption, but it's all on a secure and private network so there are no man-in-the-middle concerns. I should have mentioned that in my post, this is a special case, and I'm looking for a special solution, but there may not be one. Thanks! – rjcarr Jan 28 '12 at 21:41
  • Just use a trustmanager to load your truststore.It is very simple for your case.You could also configure it to accept ANY certificate – Cratylus Jan 28 '12 at 22:01
  • This http://www.exampledepot.com/egs/javax.net.ssl/trustall.html disables ANY validation – Cratylus Jan 28 '12 at 22:03
0

As much as I hate to say this, sometimes it's better to just go with the flow.

Java is attempting to make applications more secure through the use of proper SSL verification practices. In this case, it is succeeding: had you been able to tell the program "it's okay, accept the untrusted self-signed certificate", your program would have been vulnerable to a man-in-the-middle attack where Mallory puts his server (with its own self-signed certificate, just as valid as yours!) in between the host and the target it's attempting to communicate with. Then he proceeds to read all the traffic you thought was nice and safe, and you don't even notice.

So, your assertion that telling Java to "trust any self-signed certificate when connecting to this host" is secure is, regrettably, not correct.

You can get free, totally valid SSL certificates from StartSSL. They're good folks.

Borealid
  • 95,191
  • 9
  • 106
  • 122
  • I understand the man-in-the-middle concerns, but my application runs in a closed environment (which really doesn't even need SSL but they use it anyway), so there is no chance of a problem. That's why I'm saying this is a special case and can be handled differently, and I'm asking for a solution to that, but it might be so special that there isn't any way to accomplish it, so I may have to go the route of updating the trust stores. Thanks for the help! – rjcarr Jan 28 '12 at 21:28
  • @rjcarr I'm sorry, the only ways I know of doing this would be to ship a custom trust store and use that, but you explicitly said you have no access outside the JVM. It's probably easiest to get a trusted cert. – Borealid Jan 28 '12 at 21:30
0

That's how PKI is supposed to work - you must have complete chain of trust from some trusted certificate stored in you keystore to your certificate. So you can

  • set you certificate as trusted
  • ask somebody already trusted (i.e. with trusted certificate in the keystore) to sign you certificate

Trying to bypass that is not good bad idea. You can install you certificate in some Java post-install hook, you may have some cron job checking it periodically or do it in exception handling. You can even download this way a certificate from the server and install it everytime it changes (extracting the cert with openssl is easy). But for god's sake, if you decide to do such thing, at least write some audit log about it to some third machine a make sure somebody reads it.

You can also write "hacker-friendly" on you doors. :)

Rostislav Matl
  • 4,294
  • 4
  • 29
  • 53
0

(Note that when you're talking about "keystore" in your question, you're in fact talking about the trust store (which is a keystore). More details on this unfortunately confusing Java terminology are in this answer.)

My application will only make calls to a single server so if there was a way to bypass the self-signed restrictions, and never consult keystores, it wouldn't be a security problem, but is there a way to do this?

Actually, it would be a security problem. Your application may indeed be intended to call only a single server, but the trust store is precisely there to help make sure you're connecting to the machine you intended to connect to. Without it, you wouldn't be able to know whether you're connecting to that server or a MITM server.

If you want the security provided by SSL/TLS, don't bypass these rules. (In particular, don't use a trust manager that will accept any certificate.)

I've looked around and the only solutions I've found is to add the certificate to the java key store, but this is a problem for me because I have no control over when or how they update java, and I've read that the keystore isn't preserved between updates, and I have no access to the system outside of the JVM.

Quoting myself from this answer (to a more specific question):

The right way is to import this self-signed certificate into the client's trust store, using keytool for example:

keytool -import -file server-cert.pem -alias myserver -keystore mytruststore.jks

You can either do it directly in the JRE's trust store (lib/security/cacerts), which may lack some flexibility, or do it in your own copy of this file, which you then set as the trust store (the default password is changeit or changeme on OSX). You configure this truststore globally for your application using the usual javax.net.ssl.trustStore* system properties (e.g. -Djavax.net.ssl.trustStore=mytruststore system property (and -Djavax.net.ssl.trustStorePassword`). [...]

You don't actually have to use the trust store provided by the JRE (and which may be updated regularly). You could import your self-signed cert into a new empty keystore, which you'll use as a trust store within your application (don't import the private key with it). How to discuss trust store management was in fact discussed in this question: nothing prevents you from using a different trust store specifically for your application or part of it (and in fact Sun/Oracle make no guarantee as to the suitability of the default trust store).

I'm building an application that needs to open self-signed HTTPS SSL URLs in java. I've learned that you can bypass the SSL problems by adding a call to HttpsURLConnection.setDefaultHostnameVerifier() where you say what hostnames are allowed.

While it may indeed by slightly less of a problem if you only have a single self-certificate in your trust store, host name verification is also an essential component of the security provided by SSL/TLS. Don't bypass it, verify that the certificate you're connecting to matches the name you're trying to connect to. (To make an analogy, if you want to check someone's identity, you not only want to check the their passport was emitted by a country whose passports you trust, but you'll also want to check they have the right name inside, otherwise you could be in front of anyone from that country.)

Making the CN= RDN of the Subject Distinguished Name of your self-signed certificate be the host name of the server should be enough, although it's the legacy way of doing it. You may also want to add the Subject Alternative Name extension. More on this in this answer.

Generally speaking do not bypass the SSL "problems". These mechanisms are precisely in place to make the usage of SSL/TLS secure.

Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376
  • Thanks for the comment, it makes a lot of sense, but I didn't go into enough detail about how special of a case mine is (being a locked down, private network). But I appreciate the time for your response. – rjcarr Jan 30 '12 at 22:20
  • @rjcarr No problem. Still not clear as to why you would just need encryption. Can anyone on your network sniff packets and use their network card in promiscuous mode, for example? – Bruno Jan 30 '12 at 22:27
  • Sorry, I can't get into the details ... let's just say if there's a way to add a layer of security, even if there's no point to it, these people will do it. I don't make the rules I just play by them. :) – rjcarr Jan 31 '12 at 17:25
  • That's precisely why I always discourage using trustmanagers that trust any server: it will please the people in charge of ticking the SSL box on the to-do list, but it won't actually make the product secure. (The item on the requirement list should say "Have configured SSL properly?" instead of only "Have we turned on SSL?".) Anyway, I understand it's not always up to you... :-) – Bruno Jan 31 '12 at 17:48