SSLContext initialization - java

I'm looking at the JSSE reference guide, I need to obtain an instance of SSLContext in order to create a SSLEngine, so I can use it with Netty to enable security.
To obtain an instance of SSLContext, I use SSLContext.getInstance(). I see that the method is overridden multiple times, so I can chose the protocol and security provider to use.
Here, I can see the list of algorithms that can be used. Which algorithm should I use to enable secure communication?
Also, since it is possible to specify the security provider to use, which provider should I use?
Thanks

As you can see in the standard names documentation, all entries (SSLv3, TLSv1.0, TLSv1.1, ...) say that they may support other versions.
In practice, in the Oracle JDK (and OpenJDK), they all do. If you look at the source code, the TLS10Context class is what's used for TLS, SSL, SSLv3 and TLS10, TLS11Context is used for TLSv1.1 and TLS12Context for TLSv1.2. All support all versions of SSL/TLS, it's what's enabled by default that varies.
This may be different with another provider or JRE vendor. You should of course pick one that's at least going to support the protocol version you want to use.
Note that the protocol used is determined later on using SSLSocket.setEnabledProtocols(...) or its SSLEngine equivalent.
As a general rule, use the highest version number you can (SSLv3 < TLSv1.0 < TLSv1.1 ...), which may depend on what the parties with which you want to communicate support.
Which protocols are enabled by default varies depending on the exact version of the Oracle JRE.
When looking at the source code for sun.security.ssl.SunJSSE in OpenJDK 7u40-b43, TLS is simply an alias for TLSv1 (and so are SSL and SSLv3), in terms of SSLContext protocols. Looking at the various implementations of SSLContextImpl (which are inner classes of SSLContextImpl itself):
All support all protocols.
All protocols are enabled on the server side by default.
the client-side protocols enabled by default vary:
TLS10Context (used for protocol SSL, SSLv3, TLS, TLSv1) enables SSLv3 to TLSv1.0 by default on the client side.
TLS11Context (used for protocol TLSv1.1) also enables TLSv1.1 by default.
TLS12Context (used for protocol TLSv1.2) also enables TLSv1.2 by default.
If FIPS is enabled, SSL is not supported (so not enabled by default).
This changes in Java 8, in conjunction with the new jdk.tls.client.protocols system property.
Again, when looking at the source code for sun.security.ssl.SunJSSE in OpenJDK 8u40-b25, SSLContext protocols TLSv1, TLSv1.1, and TLSv1.2 also make use of TLS10Context, TLS11Context and TLS12Context, which follow the same logic as in Java 7.
However, protocol TLS is no longer aliased to any of them. Rather, it uses TLSContext which relies on the values in the jdk.tls.client.protocols system properties. From the JSSE Reference guide:
To enable specific SunJSSE protocols on the client, specify them in a comma-separated list within quotation marks; all other supported protocols are then disabled on the client. For example, if the value of this property is "TLSv1,TLSv1.1", then the default protocol settings on the client for TLSv1 and TLSv1.1 are enabled on the client, while SSLv3, TLSv1.2, and SSLv2Hello are disabled on the client.
If this property is empty, all protocols are enabled by default on both client and server side.
Of course, in recent versions of Oracle JRE 8, SSL is also completely disabled by default (so removed from those lists).
Note that in both cases (JRE 7 and 8), the SSLContext you get by default via SSLContext.getDefault() out of the box is more or less equivalent to an SSLContext obtained with protocol TLS and initialised with the default truststore parameters and so on.

There is no default for the protocol, so I would use the latest one supported by your JDK, which is either TLSv1, TLSv1.1 or TLSv1.2: see which works, or have a look at getSupportedProtocols(). The default security provider is used by avoiding all the APIs where you specify it, or else e.g. KeyStore.getDefaultType().
And when you come to get your SSLEngines, make sure you use the method that takes a hostname and port. Otherwise you will get no SSL session sharing.

Related

Is there a way to make the IBM JVM use standard RFC cipher suite Names?

All IBM cipher suite names begin with SSL_ even though standards say some should begin with TLS_. Is there an option to make the JVM use the standard names so I dont' have to create special include/exclude rules to get Jetty 9 to work with SSL? An option that does this is mentioned in the following link but I can not find any doc on what the option name is or how to set it.
https://github.com/eclipse/jetty.project/issues/2921
https://www.ibm.com/developerworks/community/forums/html/threadTopic?id=9b5a56a9-fa46-4031-b33b-df91e28d77c2
The IBM J9 JVM only allows interop with the RFC names when declaring the precise list of Cipher Suites to use.
In other words, it wont ever return the RFC names in the supported lists, but will use the RFC names when you declare what you want to use.
This decision by the IBM J9 JVM is incompatible with many projects.
When using the IBM J9 JVM you have to declare the entire list of Cipher Suites you want to use with any product that uses an SSLEngine on the IBM J9 JVM. (HTTP Clients, WebSocket Clients, REST Clients, HTTP Servers, etc...)
On Jetty, you will need to create a custom SslContextFactory to behave in the IBM J9 JVM way, not using RFC Name patterns for inclusion / exclusion. Override the following method and implement it your IBM J9 JVM way.
public SSLParameters customize(SSLParameters sslParams)
{
super.customize(sslParams);
_selectedCipherSuites = // String[] of selected cipher suites on IBM J9
sslParams.setCipherSuites(_selectedCipherSuites);
}
And alternate approach, that would be more wholesome, is to create a new registered security provider (say "myIbmRFC") that can return a SSLContext which uses the RFC names.
It would have to support ...
String protocol = "TLS";
String provider = "myIbmRFC";
SSLContext context = SSLContext.getInstance(protocol, provider);
context.init(....); // read javadoc about this
SSLParameters enabled = context.getDefaultSSLParameters();
SSLParameters supported = context.getSupportedSSLParameters();
// these two should return RFC names (a mapping between IBM and RFC)
String[] enabledCipherSuites = enabled.getCipherSuites();
String[] supportedCipherSuites = supported.getCipherSuites();
Note: You cannot use HTTP/2 on IBM J9 JVM. The TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 Cipher that is mandated by the RFC cannot be discovered, so it winds up failing the HTTP/2 initialization. If you do manage to get past this, then the list of Blacklisted Cipher Suites from the HTTP/2 RFC use the RFC names as well, and cannot be overridden, so that will increase your likelyhood of generating a INADEQUATE_SECURITY from the remote endpoint to a near certainty as you will be using a blacklisted Cipher suite that wasn't excluded by Jetty's HTTP/2 layer.

How to enable TLSv1.2 in JAVA 7u80 client

We have a java application which runs on Java Version: 1.7.0_80 and we are trying to enable TLSv1.2 with the jvm argument -Dhttps.protocols=TLSv1.1,TLSv1.2
-Djdk.tls.client.protocols=TLSv1.1,TLSv1.2-Ddeployment.security.TLSv1=false
-Ddeployment.security.TLSv1.1=true
-Ddeployment.security.TLSv1.2=true to consume a web service which supports only TLSv1.2. Though we have the jvm argument java client still using TLSv1 for communicating with web services,
can someone please help me is there any jvm configurations I need to make to use TLSv1.2 without any code change?
Without any code change, as I wrote in the comment, you need at least 7u95.
jdk.tls.client.protocols system property. To enable specific SunJSSE
protocols on the client, specify them in a comma-separated list within
quotation marks; all other supported protocols are then disabled on
the client. For example, if the value of this property is
"TLSv1,TLSv1.1", then the default protocol settings on the client for
TLSv1 and TLSv1.1 are enabled on the client, while SSLv3, TLSv1.2, and
SSLv2Hello are disabled on the client. This propery has been available
since Java SE 7u95.
The same property is also available since Java 6u121, with Java 6 supporting and implementing TLS 1.2.

How to configure what TLS version is used for JMX over SSL?

I need to configure TLSv1.2 for JMX communication.
Unfortunately I can not find the appropriate configuration here:
https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html
How to configure what TLS version is used for JMX over SSL?
PCI DSS 3.1 does not allow usage of TLS 1.0.
You have obviously not read the documentation you have linked. It says:
com.sun.management.jmxremote.ssl.enabled.protocols: Default SSL/TLS protocol version.
com.sun.management.jmxremote.ssl.enabled.cipher.suites: Default SSL/TLS cipher suites.
This should solve your problem. After you have configured that, scan your JXM port with sslscan with a recent version (1.0.2+) of OpenSSL.

SSLHandshakeException while connecting to a https site

I am trying to record a https site through jmeter (version 2.13, java version - 1.8u31) and I am getting SSLHandshakeException while connecting to a https site. The error message is
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2011)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1113)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:436)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
at org.apache.jmeter.protocol.http.sampler.MeasuringConnectionManager$MeasuredConnection.open(MeasuringConnectionManager.java:107)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:643)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.executeRequest(HTTPHC4Impl.java:517)
at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.sample(HTTPHC4Impl.java:331)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy.sample(HTTPSamplerProxy.java:74)
at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1146)
at org.apache.jmeter.protocol.http.proxy.Proxy.run(Proxy.java:240)
I have turned on debug logging for SSL but I wasn't able to understand the root cause. It seems that the java client sends the ClientHello but does not receive the ServerHello message (where the server chooses the highest version of SSL and the best cipher suite that both the client and server support and sends this information to the client). I see differences between the protocol versions being sent, read and received by the client (TLSv1.1 vs TLSv1.2)
Is this the root cause ? If so, how can I fix it?
The logs are pasted here - Java SSLHandshakeException Logs - Pastebin.com
Update
As #Anand Bhatt suggested, I analyzed the site with ssllabs and understood the following
The server does not support TLSv1.2 which is supported by java 8
The server supports only one cipher suite - TLS_RSA_WITH_AES_256_CBC_SHA
Java 8u31 doesn't support the cipher suite that the server supports and that's most probably the issue.
Does that sound right? If so, how do we make the java 8 client support the cipher suite that the server supports?
SSLlabs is apparently testing "out of the box" support. Java crypto has a crock dating back to the 1990s when the US government severely restricted export of crypto software,
and as a result the JRE (or JDK) as distributed by then-Sun now-Oracle does not permit use of 256-bit symmetric encryption, which your server is demanding. You must download and install
the "JCE Unlimited Strength Jurisdiction Policy Files" for your Java (major) version; 8 is at http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html .
The README in the file gives longwinded details, but basically you replace two tiny jar files in JRE/lib/security.
TLSv1.2 is not a real issue now. TLS protocol automatically negotiates the highest version supported (and enabled) by both ends.
Java 8 implements SSLv3, TLSv1.0, TLSv1.1 and TLSv1.2, but recent updates (8u31 or 7u75 and up) disable SSLv3 by default because of POODLE;
you can re-enable it if you choose, but you should be reluctant to. (Java 7 implements the same protocol versions, but client by default disables 1.1 and 1.2 because of compatibility concerns at its release several years ago.)
However, because of POODLE and BEAST some security authorities no longer accept SSLv3 and TLSv1.0
as adequately secure; an important example is credit and debit cards, as detailed in https://security.stackexchange.com/a/87077/39571 .
TLSv1.2 includes some technical improvements over 1.1, making it preferred today, and there might be future discoveries that make those
improvements crucial; if your server can't support 1.2 (and maybe higher) at that point you would be in trouble. Similarly the fact that the server's only
supported suite uses plain-RSA key-exchange, i.e. NOT forward secrecy, is considered suboptimal now, and over time may become unacceptable.
keytool (at least with the normally used keystore and truststore files) has nothing to do with symmetric cryptography.
It could likely be relevant if the server uses a CA root (or more exactly and slightly more general, trust anchor)
that your JRE and/or application does not trust, and/or if the server wants client authentication at SSL/TLS level,
which is fairly rare. (Most websites authenticate at the web-application level, or at least HTTP level, if at all.)
SSLLabs checking of the server cert chain (and several other things also) is generally stricter than Java's, and they
didn't complain in that area, so it's unlikely you have a problem there.

Java http clients and POODLE

Regarding the POODLE vulnerability, if I understand it correctly, it requires a client that automatically downgrades TLS protocol to SSLv3 when failing to establish a secure channel with a server using higher version protocol advertised by the server.
Do the common java HTTP client libraries, specifically javax.net.ssl.HttpsURLConnection and Apache HttpClient, automatically downgrade the TLS protocol when failing to establish TLS session with a server? If not, am I correct that they are immune from he POODLE attack unless either (a) the server only supports SSLv3, or (b) a logic at a higher level performs the downgrade?
I'm looking for something like http://blog.hagander.net/archives/222-A-few-short-notes-about-PostgreSQL-and-POODLE.html but for Java clients.
Apache HttpClient does not implement any of the TLS protocol aspects. It relies on JSSE APIs to do TLS/SSL handshaking and to establish secure SSL sessions. With the exception of SSL hostname verification logic, as far as TLS/SSL is concerned Apache HttpClient is as secure (or as vulnerable) as the JRE it is running in.
Update: HttpClient 4.3 by default always uses TLS, so, unless one explicitly configures it to use SSLv3 HttpClient should not be vulnerable to exploits based on POODLE.
This turned out to be wrong. One MUST explicitly remove SSLv3 from the list of supported protocols!
SSLContext sslContext = SSLContexts.custom()
.useTLS() // Only this turned out to be not enough
.build();
SSLConnectionSocketFactory sf = new SSLConnectionSocketFactory(
sslContext,
new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"},
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(sf)
.build();
Update 2: As of version 4.3.6 HttpClient disables all versions of SSL (including SSLv3) by default.
You MUST disable SSL v3.0 on java clients if you use https.
This can be done by adding this property on java 6/7:
-Dhttps.protocols="TLSv1"
And for Java 8 :
-Dhttps.protocols="TLSv1,TLSv1.1,TLSv1.2"
-Djdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2"
Source :
http://www.oracle.com/technetwork/java/javase/documentation/cve-2014-3566-2342133.html
Apache HttpClient 4.3.6 disables SSLv3 by default.
Here's an excerpt from Apache HC 4.3.6 release notes
Release 4.3.6
HttpClient 4.3.6 (GA) is a maintenance release that fixes several
problems with HttpClient OSGi bundle as well as some other issues
reported since release 4.3.5.
Please note that as of this release HttpClient disables all versions
of SSL (including SSLv3) in favor of the TLS protocol by default.
Those users who wish to continue using SSLv3 need to explicitly
enable support for it.
Users of all HttpClient versions are advised to upgrade.
Changelog:
SSLv3 protocol is disabled by default Contributed by Oleg Kalnichevski
Update: If you are running on JVM having version >= Java 1.8 Update 31 SSLv3 is disabled by default.Check out the release notes
After spending considerable time trying to figure out why TLSv1.2 was being used despite setting -Dhttps.protocols="TLSv1" we finally found this post.
The magic flag is indeed -Djdk.tls.client.protocols="TLSv1" and our Apache Axis 1.4 client works again.
So in case you move from Java 7 to Java 8 you may need to add this flag as pre JAVA 8 used TLSv1 as default whereas JAVA 8 uses TLSv1.2
Thanks!

Categories

Resources