Can a signed certificate be used without importing explicitly? - java

I've read a lot of articles regarding the import of a cert, but I am still unclear on a couple things.
When connecting to an SSL site from a Java application [in this case, a JBOSS web app], does the client cert need to be explicitly installed on the application server prior?
I can install a client cert manually, but there is an expiration date. So I'll need to manage the expiration dates of all client installed certs on our application server, and take an outage to update each one.
It feels like there should be a better way.
Shouldn't the application automatically accept a valid signed cert? [In this case, it is signed by VeriSign]
We are getting an exception currently when trying to access an https url from the application without explicitly installing the cert.
The API proxy library is swallowing the internal exception, so I dont know the details.
If the cert should be accepted automatically, then there may be a different issue here...

Can a signed certificate be used without importing explicitly?
Yes, it does not need to be installed prior to use. In fact, if you know in advance of what to expect, then you can include that information into the application. That has an added benefit of improving the application's security posture.
To avoid importing the certificate, use a custom X509TrustManager and override checkServerTrusted. In checkServerTrusted, ensure the server's public key is expected (i.e., pin the server's certificate or public key); or verify the server's certificate is valid (i.e., is within validity and forms a chain to your trusted root).
When connecting to an SSL site from a Java application [in this case, a JBOSS web app], does the client cert need to be explicitly installed on the application server prior?
In the case of client certificates, the server advertises the issuer whom it relies upon to issue client certificates. So the server will need to know the trust point for issuing client certifcates for authenticating clients.
In this case, it is signed by VeriSign
This could be really bad. In this case, you will trust all of your clients signed under the Verisign PKI, and all of Verisign's other clients signed under the Verisign PKI.
In this case, it would probably be better to avoid public CAs and run your own PKI (i.e., be your own CA). In this case, pick up a copy of Network Security with OpenSSL. The book will show you how to accomplish the customary tasks using both the openssl command and programmatically.

Related

SSL: Client Authentication, multiple certificate version in same store

Here is the situation:
Our Application talks to multiple 3rd party applications and few of them need client authentication.
One particular third party app needs client auth and has appropriately provided certificates (which we imported in our key store (JKS)). This is during integration testing. Things are working fine in the Test environment.
Now before going live, they want to upgrade the certificate issued by an CA.
For the new certificate, we can always create a new store, but for the sake
of convenience wanted to know if the two certificates(old and new) can reside in the same store? (So that in case they rollback, there is no change on our side)
URL being same, how does the application(http-client library) knows which client certificate(s) version to present when making calls to server?
You can have both certificates in the truststore. JSSE will select whichever one matches the trusted CAs the server advises when it requests the client certificate.
However the scenario you describe is radically insecure. If you are the client, you should be providing your own client certificate, not one that comes from someone else. Otherwise there must be a compromise of the private key, which means the certificate can't be used for the purpose it is intended for, and you can legally repudiate all transactions that are supposedly authenticated via this means. Client authentication under such a scheme serves no useful purpose whatsoever and you should not waste further time on it.

A straight forward way to open self-signed HTTPS SSL URLs in java?

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?
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
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.
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. :)
(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.

CXF SSL secured Web Service client with multiple certificates

I have a Java CXF client that connects to a SSL secured Web Service with mutual authentication.
I have my keystore and my truststore properly configured on the client-side and it works fine.
I am concerned here by the fact that my keystore contains only one client certificate and on the CXF configuration it is not possible to say "ok for this SSL communication you'll use this certificate".
As I only have one certificate it's not difficult to choose the good one for CXF durign SSL handshake.
But this client will be deployed in a environment where it will be used with multiple possible client having their own certificate and each of them will be signed by the same certification authority. When the server will ask for a client certificate that is signed by a specific authority, there will be no way to distinguish one certificate from another.
How can I tell CXF (or Java) to use the proper certificate in this context?
Do I need to build as many SSL context as client certificates? (ie. having N keystore each of them containing only one certificate).
Or is there a way (in CXF conf or in Java) to say "use this certificate in this context"?
Thanks in advance for your help.
All the certificates must refer to the same client, otherwise the CAs are derelect in their duty. So they should all have for example the same subjectX500Principal. So why do you need a specific certificate? All of them identify the same client, so from an authentication point of view they are all equivalent.
It's starting to sound as though you want to use a particular certificate for authorization purposes, not just to establish identity via authentication. If so it is the wrong approach, a misuse of PKI. Authorization is an application-controlled step once you have an authenticated identity: get the identity of of the peer certificate and look up your authorization database to see if that identity is allowed to access this part of the application. Don't try to use a cacerts file as an authorization database, that's not what it's for.
I don't know if this is an option for you but I've done dynamic alias selection using WSIT before (i.e. one keystore, many private key entries). See this article for more detail. (Let me know if that article isn't enough - I can post more detail if you need)

Can I create self-signed certificate in Java which will be automatically trusted by web browsers?

I've generated a self-signed certificate for my Java app using keytool. However, when I go to the site in a browser it always pops up with a warning - saying this site does not own the certificate - is there a way to self-sign/doctor a certificate so I won't get these warnings in a browser? Both server and browser are located on the same host and I navigate to the site using "http://localhost/". I do not want to add an exception to the browser because I have tests which run on a big build farm so it is excessive to add an exception to all browsers on all build machines.
No, you can't. You might as well ask "How can I make a fake certificate for hsbc.com?"
There are two ways to get a browser to accept a certificate:
Buy a certificate for a domain from a trusted authority (which means proving to that authority that you own that domain) and then use that domain as the name of your test servers
Install your signing certificate into the browsers, so that you effectively become a trusted authority for that browser.
Without touching the browsers, there's no other way to do it - how could there be, if the internet is to remain secure?
You could also setup a self-signed Certificate Authority (CA) using OpenSSL or possibly your Java tool. You can then use that CA to sign a number of server certs.
You are still going to need to manually trust your self-signed CA on all clients that access your test servers, but at least you only have to trust one root CA, rather than a bunch of individual self-signed server certs.
Another option is to check out CAcert.
Is the certificate you created for localhost or for test.textbox.com? If you create a certificate for the FQDN test.textbox.com, that's how you need to be reaching the server to not get those errors, as long as the certificate is properly signed. You can't generate a certificate for the FQDN and then use an IP or an alias (localhost) to access it without being warned that things aren't matching up properly. Or am I misunderstanding your problem?
Make the certificate for "localhost" instead. It needs to match the hostname you have in the URL.
You will still be bothered as the certificate is not trusted, but that is another issue.

Enabling https for Java Webstart

I have a swing application deployed in HTTP Server. Users use the browser to point an URL and install the client using java webstart. Now I need to enable https access to my application deployed on HTTP server. I am using JDK 1.5 as default jdk supported in the jnlp file. For time being I use a self signed certificate to the sign the jars (by default created using Sun's jarsigner, keytool, etc, utils).
Solution/steps would be much appreciated.
Thanks in advance
Ramesh
As far as I understand your question you don't need to change anything to your code of the client. If you only want to give access to the JNLP via HTTPS you would only need to reconfigure the application server distributing the JNLP or if you have a webserver in front of the application server (as we do here: user - https -> apache -> AJP -> tomcat) you need to reconfigure the webserver to allow the access to the JNLP via HTTPS.
You need to enable HTTPS on the web server. To get the certificate you need to provide credentials and the host name of the server to a certificate authority (CA) like VeriSign or Thawte. They can provide you with a server certificate signed by their root certificate or some intermediate certificate. This certificate must then be imported into the web server to enable HTTPS over SSL. The web clients, like a browser or webstart will then verify the certificate chain when accessing the server.
If you use a self signed jar, all your users will be presented with a warning message about potentially unsafe code. To avoid this you should get a code signing certificate from a CA, which would be somewhat similar to the web server certificate. This CA-provided certificate can be imported into the keystore and used in the same way you use the self signed certificate. The code signing certificate will be signed by the CA so that the certificate chain can be verified by webstart.
What is the feature of https that you are hoping to leverage?
The signing/server authentication is done by code signing, though you are undermining this using a self-signed certificate.
Does your application code contain secrets that must be hidden from eavesdroppers?
As you say you "need to enable" there must be an underlying reason.
I believe that before you "need https" you need a proper code signing certificate. You might want to rephrase your question so that your underlying problem can be solved instead of the very specific question.

Categories