Is there a DTLS implementation in JSSE - java

I want to implement a DTLS 1.0 client in Java and after googling a bit I found that the JSSERefGuide says the following:
The JSSE API is capable of supporting SSL versions 2.0 and 3.0 and TLS
version 1.0. These security protocols encapsulate a normal
bidirectional stream socket, and the JSSE API adds transparent support
for authentication, encryption, and integrity protection. The JSSE
implementation shipped with the JDK supports SSL 3.0, TLS (1.0, 1.1,
and 1.2) and DTLS (version 1.0 and 1.2). It does not implement SSL
2.0.
So I thought I could implement it in pure Java without using any library (e.g. BouncyCastle)
But when I try running (and a few other, like DTLSv1.2, DTLSv1...):
final SSLContext sslContext = SSLContext.getInstance("DTLSv1.0", "SunJSSE");
It throws:
Exception in thread "main" java.security.NoSuchAlgorithmException: no such algorithm: DTLSv1.0 for provider SunJSSE
at sun.security.jca.GetInstance.getService(GetInstance.java:87)
at sun.security.jca.GetInstance.getInstance(GetInstance.java:206)
at javax.net.ssl.SSLContext.getInstance(SSLContext.java:199)
while for example the following works:
final SSLContext sslContext = SSLContext.getInstance("TLSv1.2", "SunJSSE");
Listing all Security Providers I find no DTLS stuff at all.
So is there actually a DTLS implementation? And if so how are you supposed to use it?

You can use https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/test/jdk/javax/net/ssl/DTLS/DTLSOverDatagram.java (or https://github.com/twosigma/OpenJDK/blob/master/test/jdk/javax/net/ssl/DTLS/DTLSOverDatagram.java , its the same)
For the person which killed my previous answer because of the links: Even if the link breaks this is no problem - because at looking at the link you'll see with ease that DTLSOverDatagram is part of the official open-jdk 11 tests - so even if the link vanishes you can easily find other sources.
While these are tests for the DTLS implementation, with little refactoring this can be used as a base for DTLS over (udp-) datagrams. For both client and server - in fact, they are almost the same.

The doc is right and you get an Exception because there is no DTLS protocol :
https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext
Choosing DTLS comes at the moment of creating the socket, as it will be one of TCP or datagram types. As beginning, it will look like :
DatagramSocket s = new DatagramSocket();
...
final SSLContext sslContext = SSLContext.getInstance("TLSv1.0", "SunJSSE");
sslContext.init(null, yourSSLTrustManager, null);
SSLSocketFactory factory = (SSLSocketFactory)sslContext.getSocketFactory();
SSLSocket daSocket = (SSLSocket) factory.createSocket(s, host, port, false);

DTLS is present in JavaSE 9: SSLContext Algorithm Names

Related

SOAP Web service not accepting the request because of incompatible TLS

I'm trying to make a third-party SOAP service call that uses HTTPS from local (development environment) AEM 5.6.1. The SOAP service accepts the requests with a minimum TLS Protocols of TLSv1.1.
I have AEM 5.6.1 that uses JDK7 and for JDK7 the default TLSv1.
To achieve the minimum acceptable TLS. I tried the below two approaches:
Approach 1:
Made AEM start with -Dhttps.protocols=TLSv1.2
Approach 2:
Updated the SSLContext to update TLS.
SSLContext context = null;
try {
context = SSLContext.getInstance("TLSv1.2");
context.init(null, null, new java.security.SecureRandom());
SSLContext.setDefault(context);
LOGGER.info("Currecnt TLS:" + SSLContext.getDefault().getProtocol());
}catch (Exception e){
LOGGER.error("Error while updating TLS:",e);
}
First one doesn't work will, but the other one to update the TLS protocol for AEM to TLSv1.2.
But I'm still unable to access the service. The error remains the same.
Error:
The required TLS connection level has not been met. SSL Protocol level: TLSv1
Reference:
https://stackoverflow.com/a/42291244/4802007
https://stackoverflow.com/a/32346644/4802007
I would like to know 2 things here,
Am'I missing anything that is stopping the proper TLS update.
Is there any way to update the TLS only for this particular service, instead of changing it globally.
Thanks
This is a bug in CQ 5.5/5.6. The core issue boils down to the fact that in older CQ version SSLv3 was not allowed to be disabled by config and therefore TLS parameters never took effect.
You need to contact Daycare support and ask for a hotfix for your version.
Alternatively, check out this HF from your package share account: HOTFIX-5220 as this may have the fix for your TLS issue.
AEM 6.0 released a hotfix for this issue available via package share. Use your login and search for HOTFIX-5238 under 6.0 and ask Daycare for a back port or a compatible package for your version of AEM if the above mentioned hot fix does not work for you.

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!

HttpClient supporting multiple TLS protocols

We're writing an app that must communicate with a few servers using HTTPS.
It needs to communicate with AWS (using the AWS libraries) and also with some of our internal services that use TLS 1.2.
I started off by changing my HttpClient to use a TLS 1.2 SSLContext:
public static SchemeRegistry buildSchemeRegistry() throws Exception {
final SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(createKeyManager(), createTrustManager(), new SecureRandom());
final SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("https", 443, new SSLSocketFactory(sslContext)));
return schemeRegistry;
}
and injecting this SchemeRegistry into the DefaultHttpClient object (via spring), but doing that I get errors from AWS and so I assume (I may be wrong) that AWS doesn't support TLS 1.2 (I don't get this message if I just use the normal DefaultHttpClient):
AmazonServiceException: Status Code: 403, AWS Service: AmazonSimpleDB, AWS Request ID: 5d91d65f-7158-91b6-431d-56e1c76a844c, AWS Error Code: InvalidClientTokenId, AWS Error Message: The AWS Access Key Id you provided does not exist in our records.
If I try to have two HttpClients defined in spring, one that uses TLS 1.2 and one that is the default, I get the following error, which I assume means that Spring doesn't like instantiating and autowiring two HttpClient objects:
SEVERE: Servlet /my-refsvc threw load() exception
java.lang.NullPointerException
at com.company.project.refsvc.base.HttpsClientFactory.<clinit>(BentoHttpsClientFactory.java:25)
...
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1031)
at
...
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
I haven't used HTTPS much in java so could you kind people give me some advice please?
1) How would I get Spring to allow two HttpClient objects and for one to be wired to the AWS stuff beans and the other to be wired to the other beans for accessing the TLS1.2 services
2) Or is it possible to change the one HttpClient object to be able to try TLS1.2 (via SSLContext, or the SchemeRegistry or something) and if that fails then try TLS1.1 or 1.0?
3) If both are possible, what would be the 'better' way of doing it?
TLS has an in-built mechanism to negotiate which version of the protocol is to be used. From RFC 5246 (Appendix E):
TLS versions 1.0, 1.1, and 1.2, and SSL 3.0 are very similar, and
use compatible ClientHello messages; thus, supporting all of them
is relatively easy. Similarly, servers can easily handle clients
trying to use future versions of TLS as long as the ClientHello
format remains compatible, and the client supports the highest
protocol version available in the server.
A TLS 1.2 client who wishes to negotiate with such older servers
will send a normal TLS 1.2 ClientHello, containing { 3, 3 } (TLS
1.2) in ClientHello.client_version. If the server does not support this version, it will respond with a ServerHello containing an
older version number. If the client agrees to use this version,
the negotiation will proceed as appropriate for the negotiated
protocol.
In addition, changing the version number in SSLContext.getInstance(...) only changes which protocols are enabled by default. Setting the actual protocol versions is done with SSLSocket.setEnabledProtocols(...) (see this question). I'm not sure about the rest of the libraries you're using, but it's possible that it sets the enabled protocols somewhere.
There are a few possibilities:
What you're doing in your createKeyManager() differs from the default behaviour. If the service is using client-certificate authentication, bad configuration there would certainly lead to a 403 error.
(Less likely, I guess, but hard to say without seeing your createKeyManager() and createTrustManager()). Perhaps the server you're using isn't compatible with TLS 1.2 and the version negotiation mechanism. There is this comment in sun.security.ssl.SSLContextImpl:
SSL/TLS protocols specify the forward compatibility and version
roll-back attack protections, however, a number of SSL/TLS server
vendors did not implement these aspects properly, and some current
SSL/TLS servers may refuse to talk to a TLS 1.1 or later client.

SSLContext initialization

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.

How to avoid Diffie-Hellman for SSL connections with Java/Netty?

I am using Netty as backend in a Java-based Usenet client. The library is working fine, however, in some circumstances I can't connect to a remote server via SSL, because of exactly this error:
Java: Why does SSL handshake give 'Could not generate DH keypair' exception?
Unfortunately, it seems that for whatever reason this Java error still has not been fixed yet. And since the remote server is not under my control, I need a workaround here. One such "solution", according to the link above, is to avoid DH during SSL handshake at all (not very pretty, but maybe better than nothing).
However, I am no SSL expert, so I am not really sure how I can implement that within Netty; or better: within my solution that is based on Netty. By now I am creating connections as this:
// configure the Netty client
ClientBootstrap bootstrap = new ClientBootstrap(clSockChannelFactory);
// configure the pipeline factory
bootstrap.setPipelineFactory(channelPipelineFactory);
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("keepAlive", true);
bootstrap.setOption("child.receiveBufferSizePredictorFactory",
new AdaptiveReceiveBufferSizePredictorFactory());
// start the connection attempt
InetSocketAddress isa = new InetSocketAddress(serverAddress, port);
ChannelFuture future = bootstrap.connect(isa);
...
channel = future.getChannel();
...
Ok, that's fine, but where can I disable cipher suites before I connect the SSL socket, as desribed in the thread above?
Thanks in advance for all your help!
Kind regards, Matthias
PS: By the way, any ideas why this problem has not been addressed in Java yet?
I'm not familiar with Netty, but I would suggest following the approach in the secure chat example.
I'm not sure what default SSL/TLS keys/trust settings you have, but if you don't have a custom SSLContext, try SSLContext.getDefault().
Then, create an SSLEngine using SSLContext.createSSLEngine(). On this SSLEngine, you should be able to enable the cipher suites you want. Assuming you're using the Oracle JRE (or OpenJDK), you'll find the list of cipher suites in the Sun Provider documentation.
After this (this is the Netty-specific part), set an SslHandler using something like this (see Netty example):
pipeline.addLast("ssl", new SslHandler(engine));

Categories

Resources