3

I am trying to write a simple echo server using SSL. The first line that goes to the server is echoed exactly. When I send a second line, only the first character is echoed. The client works off of a buffered reader's read line from stdin. If I hit CR again the rest of the message comes through. The server seems to be sending all of the data. Here are output from client and server:

CLIENT:

Sending to server at 192.168.0.161 on port 9999

4 seasoNS
echo:4 seasoNS

are really good
echo:a

echo:re really good

SERVER: server listening on 9999
has cr/lf
4 seasoNS

size to send: 10
has cr/lf
are really good

size to send: 16
exiting...

Here is the client loop:

        try {
        BufferedReader consoleBufferedReader = getConsoleReader();
        sslsocket = getSecSocket(strAddress, port);
        BufferedWriter sslBufferedWriter = getSslBufferedWriter(sslsocket);
        InputStream srvrStream = sslsocket.getInputStream();

        String outMsg;
        while ((outMsg = consoleBufferedReader.readLine()) != null) {
            byte[] srvrData = new byte[1024];
            sslBufferedWriter.write(outMsg);
            sslBufferedWriter.newLine();
            sslBufferedWriter.flush();
            int sz = srvrStream.read(srvrData);
            String echoStr = new String(srvrData, 0, sz);
            System.out.println("echo:" + echoStr);
        }
    } catch (Exception exception) {
        exception.printStackTrace();
    }

This problem seemed so odd that I was hoping there was something obvious that I was missing.

dougM
  • 77
  • 1
  • 8

1 Answers1

3

What you're seeing is perfectly normal.

The assumption you're making that you're going to read the whole buffer in one go is wrong:

int sz = srvrStream.read(srvrData);

Instead, you need to keep looping until you get the delimiter of your choice (possibly a new line in your case).

This applies to plain TCP connections as well as SSL/TLS connections in general. This is why application protocols must have delimiters or content length (for example, HTTP has a double new line to end its headers and uses Content-Length or chunked transfer encoding to tell the other party when the entity ends).

In practice, you might not see when your assumption doesn't work for such a small example.

However, the JSSE splits the records it sends into 1/n-1 on purpose to mitigate the BEAST attack. (OpenSSL would send 0/n.) Hence, the problem is more immediately noticeable in this case.

Again, this is not an SSL/TLS or Java problem, the way to fix this is to treat the input you read as a stream and not to assume the size of buffers you read on one end will match the size of the buffers used to send that data from the other end.

Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376
  • Thanks so much. My prior SSL experience was with bytes and ETX - and it was pretty limited, this worked great. – dougM May 20 '14 at 13:33