[ 
https://issues.apache.org/jira/browse/HTTPCORE-442?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Christian Klauser updated HTTPCORE-442:
---------------------------------------
    Affects Version/s: 4.4.6
                       4.4.4
                       4.4.5
          Description: 
I'm running into a rather esoteric problem when reading the response to an HTTP 
request using {{httpcore-nio}} (used via CXF). On a high level we get a 
MalfromedChunkCodingException because the ChunkDecoder doesn't receive the last 
chunk ( {{"0\r\n\r\n"}} is missing  ) We see the following situation:

 * The plain text content fed into the SOAP/JAXB deserialization machinery cuts 
off mid-way through
 * *because* the {{ChunkDecoder}} threw a {{MalformedChunkCodingException}}'
 * *because* {{this.buffer.readLine}} returned false
 * *because* (not 100% sure here) {{fillBufferFromChannel}} returned -1 and we 
are looking for the next chunk size
 * *because* the last 106 bytes of the encrypted stream (see below) have never 
been decrypted
 * *because* the loop inside {{SSLIOSession#decryptData}} gets exited early if 
the {{SSLIOSession#endOfStream}} flag is set _even if the input stream still 
contains encrypted data_

{code}
state of the SSLIOSession in `this.channel` when the exception occurs: 
192.168.13.204:48888<->10.0.29.106:443[ACTIVE][r:r][ACTIVE][r][NOT_HANDSHAKING][EOF][][106][0][0][0]
{code}

Looking at past issues/commit messages, I understand why we have an early exit 
here (avoid infinite loops on connections that broke in the middle of a TLS 
packet). I'm not sure if just exiting is correct here. The documentation for 
the java 
[{{SSLEngine#unwrap}}|https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SSLEngine.html]
 method says that the engine tries to decrypt "one complete TLS network 
packet". There is no guarantee that it decrypts all remaining packets in the 
buffer.

In our particular case (106 still encrypted bytes), we have to run the 
{{unwrap}} method two more times until we have the complete response from the 
server (including the final chunk "{{0\r\n\r\n}}"). After the first additional 
call, there are still 53 encrypted bytes left.

I have attached a patch that solves this issue for us. The patch monitors 
whether the decryption loop is making progress and keeps looping even if 
{{endOfStream}} is set. It aborts after a number of iterations without clear 
progress. With this patch, we can run our entire integration test suite without 
error. Without this patch, about 1 in SOAP 200 calls fails.

The "progress measurement" logic could perhaps be simplified (only measure 
plain bytes, not also consumed encrypted bytes), but I'm not sure if that would 
still be correct.

I could also imagine that the actual bug is in the ChunkDecoder, that doesn't 
give the Channel another chance at filling the buffer, but the SSLIOSession 
code looks more suspicious to me (signalling EOF with 106 bytes left encrypted).

What do you think?

This issue occurs with all versions from 4.4.4 to the 4.4.x branch.

  was:
I'm running into a rather esoteric problem when reading the response to an HTTP 
request using {{httpcore-nio}} (used via CXF). On a high level we get a 
MalfromedChunkCodingException because the ChunkDecoder doesn't receive the last 
chunk ( {{"0\r\n\r\n"}} is missing  ) We see the following situation:

 * The plain text content fed into the SOAP/JAXB deserialization machinery cuts 
off mid-way through
 * *because* the {{ChunkDecoder}} threw a {{MalformedChunkCodingException}}'
 * *because* {{this.buffer.readLine}} returned false
 * *because* (not 100% sure here) {{fillBufferFromChannel}} returned -1 and we 
are looking for the next chunk size
 * *because* the last 106 bytes of the encrypted stream (see below) have never 
been decrypted
 * *because* the loop inside {{SSLIOSession#decryptData}} gets exited early if 
the {{SSLIOSession#endOfStream}} flag is set _even if the input stream still 
contains encrypted data_

{code}
state of the SSLIOSession in `this.channel` when the exception occurs: 
192.168.13.204:48888<->10.0.29.106:443[ACTIVE][r:r][ACTIVE][r][NOT_HANDSHAKING][EOF][][106][0][0][0]
{code}

Looking at past issues/commit messages, I understand why we have an early exit 
here (avoid infinite loops on connections that broke in the middle of a TLS 
packet). I'm not sure if just exiting is correct here. The documentation for 
the java 
[{{SSLEngine#unwrap}}|https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SSLEngine.html]
 method says that the engine tries to decrypt "one complete TLS network 
packet". There is no guarantee that it decrypts all remaining packets in the 
buffer.

In our particular case (106 still encrypted bytes), we have to run the 
{{unwrap}} method two more times until we have the complete response from the 
server (including the final chunk "{{0\r\n\r\n}}"). After the first additional 
call, there are still 53 encrypted bytes left.

I have attached a patch that solves this issue for us. The patch monitors 
whether the decryption loop is making progress and keeps looping even if 
{{endOfStream}} is set. It aborts after a number of iterations without clear 
progress. With this patch, we can run our entire integration test suite without 
error. Without this patch, about 1 in SOAP 200 calls fails.

The "progress measurement" logic could perhaps be simplified (only measure 
plain bytes, not also consumed encrypted bytes), but I'm not sure if that would 
still be correct.

I could also imagine that the actual bug is in the ChunkDecoder, that doesn't 
give the Channel another chance at filling the buffer, but the SSLIOSession 
code looks more suspicious to me (signalling EOF with 106 bytes left encrypted).

What do you think?


> SSLIOSession + ChunkDecoder: MalformedChunkCodingException with last chunk 
> left in inEncryptedBuffer
> ----------------------------------------------------------------------------------------------------
>
>                 Key: HTTPCORE-442
>                 URL: https://issues.apache.org/jira/browse/HTTPCORE-442
>             Project: HttpComponents HttpCore
>          Issue Type: Bug
>    Affects Versions: 4.4.4, 4.4.5, 4.4.6
>            Reporter: Christian Klauser
>         Attachments: httpcore-nio-SSLIOSession-eof.path
>
>
> I'm running into a rather esoteric problem when reading the response to an 
> HTTP request using {{httpcore-nio}} (used via CXF). On a high level we get a 
> MalfromedChunkCodingException because the ChunkDecoder doesn't receive the 
> last chunk ( {{"0\r\n\r\n"}} is missing  ) We see the following situation:
>  * The plain text content fed into the SOAP/JAXB deserialization machinery 
> cuts off mid-way through
>  * *because* the {{ChunkDecoder}} threw a {{MalformedChunkCodingException}}'
>  * *because* {{this.buffer.readLine}} returned false
>  * *because* (not 100% sure here) {{fillBufferFromChannel}} returned -1 and 
> we are looking for the next chunk size
>  * *because* the last 106 bytes of the encrypted stream (see below) have 
> never been decrypted
>  * *because* the loop inside {{SSLIOSession#decryptData}} gets exited early 
> if the {{SSLIOSession#endOfStream}} flag is set _even if the input stream 
> still contains encrypted data_
> {code}
> state of the SSLIOSession in `this.channel` when the exception occurs: 
> 192.168.13.204:48888<->10.0.29.106:443[ACTIVE][r:r][ACTIVE][r][NOT_HANDSHAKING][EOF][][106][0][0][0]
> {code}
> Looking at past issues/commit messages, I understand why we have an early 
> exit here (avoid infinite loops on connections that broke in the middle of a 
> TLS packet). I'm not sure if just exiting is correct here. The documentation 
> for the java 
> [{{SSLEngine#unwrap}}|https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SSLEngine.html]
>  method says that the engine tries to decrypt "one complete TLS network 
> packet". There is no guarantee that it decrypts all remaining packets in the 
> buffer.
> In our particular case (106 still encrypted bytes), we have to run the 
> {{unwrap}} method two more times until we have the complete response from the 
> server (including the final chunk "{{0\r\n\r\n}}"). After the first 
> additional call, there are still 53 encrypted bytes left.
> I have attached a patch that solves this issue for us. The patch monitors 
> whether the decryption loop is making progress and keeps looping even if 
> {{endOfStream}} is set. It aborts after a number of iterations without clear 
> progress. With this patch, we can run our entire integration test suite 
> without error. Without this patch, about 1 in SOAP 200 calls fails.
> The "progress measurement" logic could perhaps be simplified (only measure 
> plain bytes, not also consumed encrypted bytes), but I'm not sure if that 
> would still be correct.
> I could also imagine that the actual bug is in the ChunkDecoder, that doesn't 
> give the Channel another chance at filling the buffer, but the SSLIOSession 
> code looks more suspicious to me (signalling EOF with 106 bytes left 
> encrypted).
> What do you think?
> This issue occurs with all versions from 4.4.4 to the 4.4.x branch.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to