osundblad
osundblad

Reputation: 2681

Is there a DTLS implementation in JSSE

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?

Upvotes: 4

Views: 6587

Answers (5)

szymex
szymex

Reputation: 141

Another option is to use DTLS from native library like mbedtls. Here is a library that exposes kotlin (java compatible) API: https://github.com/open-coap/kotlin-mbedtls.

Upvotes: 1

Horcrux7
Horcrux7

Reputation: 24447

Bases on the sample from JDK and many try and error I have written the follow code which works in my use case:

public static final int      MAXIMUM_PACKET_SIZE = 1500;
private final DatagramSocket socket;
private final SSLEngine      engine;

public DtlsSocket( @Nonnull DatagramSocket socket, KeyManager km, TrustManager tm, boolean isClient ) {
    try {
        this.socket = socket;

        SSLContext sslCtx = SSLContext.getInstance( "DTLS" );
        KeyManager[] kms = { km };
        TrustManager[] tms = { tm };
        sslCtx.init( kms, tms, null );
        engine = sslCtx.createSSLEngine();
        engine.setNeedClientAuth( true );

        engine.setUseClientMode( isClient );
        SSLParameters paras = engine.getSSLParameters();
        paras.setMaximumPacketSize( MAXIMUM_PACKET_SIZE );
        engine.setSSLParameters( paras );

        engine.beginHandshake();

        byte[] receiveBytes = new byte[MAXIMUM_PACKET_SIZE];
        DatagramPacket receivePacket = new DatagramPacket( receiveBytes, 0, MAXIMUM_PACKET_SIZE );
        ByteBuffer receiveBuffer = ByteBuffer.wrap( receiveBytes );
        receiveBuffer.limit( 0 );

        ByteBuffer emptyBuffer = ByteBuffer.allocate( 0 );

        byte[] sendData = new byte[32768];
        DatagramPacket sendPacket = new DatagramPacket( sendData, 0, 32768 );
        ByteBuffer sendBuffer = ByteBuffer.wrap( sendData );

        while( true ) {
            SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
            switch( hs ) {
                case NEED_UNWRAP:
                case NEED_UNWRAP_AGAIN:
                    if( !receiveBuffer.hasRemaining() && hs != SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN ) {
                        socket.receive( receivePacket );
                        receiveBuffer.position( 0 );
                        receiveBuffer.limit( receivePacket.getLength() );
                    }
                    checkStatus( engine.unwrap( receiveBuffer, emptyBuffer ) );
                    break;
                case NEED_WRAP:
                    checkStatus( engine.wrap( emptyBuffer, sendBuffer.clear() ) );
                    sendPacket.setLength( sendBuffer.position() );
                    socket.send( sendPacket );
                    break;
                case NEED_TASK:
                    Runnable runnable;
                    while( (runnable = engine.getDelegatedTask()) != null ) {
                        runnable.run();
                    }
                    break;
                case NOT_HANDSHAKING:
                    return;
                default:
                    // should never occur
                    throw new SSLException( "handshake error " + hs );
            }
        }
    } catch( Exception ex ) {
        throw ErrorCode.throwAny( ex );
    }
}

private void checkStatus( SSLEngineResult engineResult ) throws IOException {
    if( engineResult.getStatus() != SSLEngineResult.Status.OK ) {
        throw new SSLException( "handshake error " + engineResult.getStatus() + " with handshake state " + engineResult.getHandshakeStatus() );
    }
}

Upvotes: 1

mifritscher
mifritscher

Reputation: 171

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.

Upvotes: 7

dsh
dsh

Reputation: 12213

DTLS is present in JavaSE 9: SSLContext Algorithm Names

Upvotes: 3

Eugène Adell
Eugène Adell

Reputation: 3174

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);

Upvotes: 2

Related Questions