¿Cómo detectar un final de transmisión correctamente, cuando se usa el cifrado TLS PSK?

He preparadoun simple caso de prueba de cliente TLS PSK Residencia enMockPSKTlsClient por el castillo hinchable.

En elmain método que llamo:

public static void main(String[] args) throws IOException {
    SecureRandom random      = new SecureRandom();
    TlsPSKIdentity identity  = new BasicTlsPSKIdentity("Client_identity", Hex.decode("1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A"));
    Socket socket            = new Socket(InetAddress.getLocalHost(), 12345);
    TlsClientProtocol proto  = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(), random);
    MockPSKTlsClient client  = new MockPSKTlsClient(null, identity);
    proto.connect(client);

    OutputStream clearOs = proto.getOutputStream();
    InputStream clearIs = proto.getInputStream();
    clearOs.write("GET / HTTP/1.1\r\n\r\n".getBytes("UTF-8"));
    Streams.pipeAll(clearIs, System.out);   // why is java.io.EOFException thrown?
}

Como pueden ver, les mando unGET / HTTP/1.1 cadena al servidor openssl, que se inicia como:

# openssl s_server \
        -psk 1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A \
        -psk_hint Client_identity\
        -cipher PSK-AES256-CBC-SHA \
        -debug -state -nocert -accept 12345 -tls1_2 -www

Después de eso llamoStreams.pipeAll () método, que es simplemente:

public static void pipeAll(InputStream inStr, OutputStream outStr)
    throws IOException
{
    byte[] bs = new byte[BUFFER_SIZE];
    int numRead;
    while ((numRead = inStr.read(bs, 0, bs.length)) >= 0) // Why is EOFException thrown?
    {
        outStr.write(bs, 0, numRead);
    }
}

Esta copiaopenssl s_server responder a la pantalla y también sorprendentemente lanza unEOFException al final:

TLS-PSK client negotiated TLS 1.2
Established session: 68e647e3276f345e82effdb7cc04649f6872d245ae01489c08ed109c5906dd16
HTTP/1.0 200 ok
Content-type: text/html

<HTML><BODY BGCOLOR="#ffffff">
<pre>

s_server -psk 1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A -psk_hint Client_identity -cipher PSK-AES256-CBC-SHA -debug -state -nocert -accept 12345 -tls1_2 -www 
Secure Renegotiation IS supported
Ciphers supported in s_server binary
TLSv1/SSLv3:PSK-AES256-CBC-SHA       
---
Ciphers common between both SSL end points:
PSK-AES256-CBC-SHA
Signature Algorithms: RSA+SHA1:RSA+SHA224:RSA+SHA256:RSA+SHA384:RSA+SHA512:DSA+SHA1:DSA+SHA224:DSA+SHA256:DSA+SHA384:DSA+SHA512:ECDSA+SHA1:ECDSA+SHA224:ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512
Shared Signature Algorithms: RSA+SHA1:RSA+SHA224:RSA+SHA256:RSA+SHA384:RSA+SHA512:DSA+SHA1:DSA+SHA224:DSA+SHA256:DSA+SHA384:DSA+SHA512:ECDSA+SHA1:ECDSA+SHA224:ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512
---
New, TLSv1/SSLv3, Cipher is PSK-AES256-CBC-SHA
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : PSK-AES256-CBC-SHA
    Session-ID: 68E647E3276F345E82EFFDB7CC04649F6872D245AE01489C08ED109C5906DD16
    Session-ID-ctx: 01000000
    Master-Key: B023F1053230C2938E1D3FD6D73FEB41DEC3FC1068A390FE6DCFD60A6ED666CA2AD0CD1DAD504A087BE322DD2C870C0C
    Key-Arg   : None
    PSK identity: Client_identity
    PSK identity hint: Client_identity
    SRP username: None
    Start Time: 1479312253
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
---
  13 items in the session cache
   0 client connects (SSL_connect())
   0 client renegotiates (SSL_connect())
   0 client connects that finished
  14 server accepts (SSL_accept())
   0 server renegotiates (SSL_accept())
  13 server accepts that finished
   0 session cache hits
   0 session cache misses
   0 session cache timeouts
   0 callback cache hits
   0 cache full overflows (128 allowed)
---
no client certificate available
</BODY></HTML>

TLS-PSK client raised alert: fatal(2), internal_error(80)
> Failed to read record
java.io.EOFException
    at org.bouncycastle.crypto.tls.TlsProtocol.safeReadRecord(Unknown Source)
    at org.bouncycastle.crypto.tls.TlsProtocol.readApplicationData(Unknown Source)
    at org.bouncycastle.crypto.tls.TlsInputStream.read(Unknown Source)
    at de.afarber.tlspskclient2.Main.pipeAll(Main.java:52)
    at de.afarber.tlspskclient2.Main.main(Main.java:44)
Exception in thread "main" java.io.IOException: Internal TLS error, this could be an attack
    at org.bouncycastle.crypto.tls.TlsProtocol.failWithError(Unknown Source)
    at org.bouncycastle.crypto.tls.TlsProtocol.safeReadRecord(Unknown Source)
    at org.bouncycastle.crypto.tls.TlsProtocol.readApplicationData(Unknown Source)
    at org.bouncycastle.crypto.tls.TlsInputStream.read(Unknown Source)
    at de.afarber.tlspskclient2.Main.pipeAll(Main.java:52)
    at de.afarber.tlspskclient2.Main.main(Main.java:44)

Mi pregunta es: ¿por qué esEOFException arrojado?

GeneralmenteInputStream.read() se supone que devuelve -1 al final de la secuencia y no arroja una excepción.

¿Cómo detectar un final de transmisión correctamente, cuando se usa el cifrado TLS PSK?

A largo plazo, me gustaría extender mi caso de prueba a un programa que actúe como proxy inverso PSK TLS frente a Jetty incorporado, y preferiría no confiar en las excepciones para detectar que el cliente ha terminado de leer o escribir.

Respuestas a la pregunta(1)

Su respuesta a la pregunta