I did a standalone java (java 1.8, I cannot upgrade it) application that is a client of a webapp. This webapp has updated the SSL connection from SSL1.2 to SSL2. My development machine can access to the webapp, the production machine has some problems. If I don't set the HostnameVerifier, I have a SSLHandshakeException (Received fatal alert: handshake_failure). If I set the HostnameVerifier in this way:
httpsConnection.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
the result is SocketException (Connection reset).
My develope machine works well without the HostnameVerifier. This means that I have some certificates installed on my PC? How can I install the same certificates into the production machine?
Related
I'm using org.apache.commons.net.smtp.AuthenticatingSMTPClient to establish connections to SMTP servers. After establishing the initial connection, I use client.execTLS() to send STARTTLS. I want to get the SMTP TLS certificate information for the certificates used by the remote server. I'm curious if it's possible to do so solely with the API offered by the org.apache.commons.net.smtp library.
Alternatively, what options do I have within the Java ecosystem to output the SMTP TLS certificate in a readable format, preferably using the socket already opened by client.execTLS()?
Java version: 11.
Found the solution. You can provide your own HostnameVerifier (null by default) to the org.apache.commons.net.smtp.AuthenticatingSMTPClient object:
client.setHostnameVerifier((hostname, session) -> {
// session.getPeerCertificates();
return true;
});
After reading the following, I'm still stuck on making the barest-minimum https://localhost stand-alone install-free webserver java app. It needs to be library-free, use Java 8, and accept connections from the browser without first installing any special client certs. I'm unclear if this is at all possible with self-signed certs because it only has to work for "localhost".
How make SSL server socket support both http & https in java?
My simple java HTTPS server only works for localhost
Simple Java HTTPS server
So far I've generated some key files using
openssl genrsa -aes128 -out privkey.pem 2048 # makes privkey.pem
openssl req -new -x509 -key privkey.pem # makes cert.crt
and I've cobbled together the bare minimum Kotlin setup function
private fun ssl():SSLServerSocketFactory {
val password = "MYPASSWORD".toCharArray()
val kmf = KeyManagerFactory.getInstance("SunX509")
val tmf = TrustManagerFactory.getInstance("SunX509")
val sslContext = SSLContext.getInstance("TLS")
// initialise the keystore
KeyStore.getInstance("JKS").let { ks->
FileInputStream("lig.keystore").use {
ks.load(it, password)
}
kmf.init(ks, password)
tmf.init(ks)
}
// setup the HTTPS context and parameters
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null)
return sslContext.serverSocketFactory
}
ssl().createServerSocket().use { serverSocket ->
serverSocket.reuseAddress = true
serverSocket.bind(InetSocketAddress(port))
logger.info { "WebServer ready and listening on ${serverSocket.localPort}" }
But I'm having trouble how to finish it off: Do I need to make a lig.keystore file? Can this even be done without installing certs on the client's browser?
There are two common approaches to getting a secure connection between a client (browser) and server via HTTPS:
You can obtain SSL certificate for the server that is signed by a Root Certification Authority (CA) that is trusted by the user's web browser by default.
You can generate a self-signed SSL certificate, and have the user import it into their web browser as a trusted cert.
What you have done so far seems to be to generate a server-side keystore with a self-signed cert in it and (more or less) configured the Kotlin server to use it. The problem is the client (browser). There is no safe way to get the browser to trust the self-signed cert without the involvement of the user or the user's sysadmin. (Safe ... as in safe for the user!)
And no legitimate CA should ever issue an SSL cert for "localhost"; e.g. https://www.ssl2buy.com/wiki/how-to-get-ssl-certificate-for-web-applications-that-runs-on-localhost
Impasse.
OK, so lets step back. The purpose of using HTTPS / SSL is to ensure that:
The user's web browser is talking to the correct server, and not some other server that is impersonating it.
The connection between the browser and the server is encrypted so that no third party can snoop on the traffic.
But you are trying to do this for a localhost connection. The localhost IP address is a loopback address. Unless the OS kernel is compromised, you are guaranteed that network packets sent via a loopback connection will not leave the host.
You can dismiss the "impersonation" problem. Assuming that the user's machine has not been compromised, nobody else can launch a "fake" server on the user's machine.
You can dismiss the "snooping" problem. Assuming that the user's machine has not been compromised:
The packets won't go off-host, so they can't be snooped on any "external" networks.
The only person who can "snoop" the packets on the loopback network is the user him / herself.
So, the solution is simple. Use "http" for your "localhost" connection. It should be secure ... assuming that the user's machine has not been compromised.
Note: if the user's machine has been compromised, then the bad guys have other ways to intercept the traffic that SSL won't protect against.
Another specific case:
I'm facing a web app from https that would load local data at http://localhost
Safari web browser blocks because of unsecure communication (http) in a secure flow (https).
This behavour could be discussed, but in that case self signed certificate for localhost would help., even with a warning from Safari browser.
I am using the Bot Connector REST API and am having trouble with the Kik channel. When I try to respond to a message, I am receiving this error:
javax.net.ssl.SSLException: hostname in certificate didn't match: <kik.botframework.com> != <*.azurewebsites.net> OR <*.azurewebsites.net> OR <*.scm.azurewebsites.net> OR <*.azure-mobile.net> OR <*.scm.azure-mobile.net>
The service URL I am using is "https://kik.botframework.com".
I am running this off of a local server at the moment. I did not have any trouble connecting with the Skype channel in this configuration, but Kik is giving me trouble.
I don't exactly have a solution, but I can explain what is the reason behind this and what you may have to double check on your side.
So, in short, this is happening because of SNI (Server Name Indication) and because of the client's inability to support SNI.
Check this answer for some insight into this issue https://serverfault.com/questions/594368/openssl-returns-different-ssl-certificate-to-that-shown-by-chrome
In this case, the same IP is hosting a bunch of domains and certificates. Most of the modern browsers support SNI and will be able to detect this and show you the right certificate (try firefox).
However, when the SSL client of a server is trying to do a handshake (without specifying 'server name'/'host name') it doesn't know which certificate to fetch, and hence fetches the core certificate.
Solution?
The client should 'indicate' that this is the host name and then it'll fetch the right certificate.
Example:
openssl s_client -connect dev.botframework.com:443
VS
openssl s_client -servername dev.botframework.com -connect dev.botframework.com:443
How to Solve this?
Skip the host name verification phase. Disabling SSL Certificate Validation in Spring RestTemplate or another Example:
Registry<ConnectionSocketFactory> registry = RegistryBuilder. <ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", new SSLConnectionSocketFactory(SSLContexts.createDefault(), new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
})).build();
The problem ended up being that the version of the HttpClient library being used my server is fairly old (4.2.5) and did not support Server Name Indication. I was able to patch it to support SNI as per here: Server Name Indication (SNI) Support. Thanks to Arka for pointing out what the issue likely was.
Since two days I get this error when connecting via HTTPS to my local application running on localhost:
Server has a weak ephemeral Diffie-Hellman public key
I use latest Mac OSX and latest Google Chrome. My application runs on a Tomcat. How can I create a new self-signed certificate that will be accepted by Google? I just want to continue to develop! So any hack is welcome.
I have an app that runs on GlassFish 3.x. It communicates to a remote server over https. In my cacerts file I've added the server certs. In my keystore.jks I added the private key the company running the remote server issued me. This works great on Glassfish 2.x, however on 3.x they remote server keeps complaining that the key I have is invalid.
If I remove the key from the keystore I get the same error. It's as if it's not even loading the key, which has got me wondering how does the app / container know which key I need
My connection code looks like this:
public class SSLSocket {
private static Logger logger = LoggerFactory.getLogger(SSLSocket.class);
private ConnectionProperties connectionProperties;
public TuSSLSocket(ConnectionProperties connectionProperties) {
this.connectionProperties = connectionProperties;
}
public SSLSocket getSSLSocket() throws Exception{
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) factory.createSocket(connectionProperties.getHost(), connectionProperties.getPort());
socket.setSoTimeout(90000);
return socket;
}
}
I set the Host and Port accordingly, but no where do I say go look for this alias in the keystore. So... how does the app know what alias to grab?
Explaining two way ssl and all that jazz is exhausting. I will try to find a useful link. However, for your information when an applicaiton deployed in glassfish acts as a client to communicating with a server over SSL ( for instance LDAP server realm configured through an SSL port), it will use glassfish server's identity certificate (from its keystore) as its client certificate.
But if you are explicitly coding for SSL handshake, client application is responsible for selecting the keystore, and presenting the certificate as part of the handshake.
Since it is working in a previous version of Glassfish, the same code should work for you. It is very likely that your problem is related to configuration. I am a bit confused about what you had added to server's keystore.jks generally the other server's certificate is added to the trust store cacerts.jks
A useful glassfish ssl example
An SSL Socket client example
Example of choosing keystore in client.
There are two ways to accomplish this
The first:
Open the following path from the admin console page.
configuration
your cluster/instance configuration.
jvm settings
jvm options
you will find this line some where in the list of items
-Dcom.sun.enterprise.security.httpsOutboundKeyAlias=s1as
Change the s1as value to the certificate alias you want to use.
The other option is to add a system property to your code
System.setProperty("com.sun.enterprise.security.httpsOutboundKeyAlias", "your certificate alias");