Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenSslEngine wrap may generate bad data if multiple src buffers #6715

Closed
wants to merge 1 commit into from

Conversation

Scottmitch
Copy link
Member

Motivation:
SSL_write requires a fixed amount of bytes for overhead related to the encryption process for each call. OpenSslEngine#wrap(..) will attempt to encrypt multiple input buffers until MAX_PLAINTEXT_LENGTH are consumed, but the size estimation provided by calculateOutNetBufSize may not leave enough room for each call to SSL_write. If SSL_write is not able to completely write results to the destination buffer it will keep state and attempt to write it later. Netty doesn't account for SSL_write keeping state and assumes all writes will complete synchronously (by attempting to allocate enough space to account for the overhead) and feeds the same data to SSL_write again later which results in corrupted data being generated.

Modifications:

Result:
OpenSslEngine#wrap will no longer produce corrupted data due to incorrect accounting of space required in the destination buffers.

@Scottmitch Scottmitch added this to the 4.1.11.Final milestone May 8, 2017
@@ -638,9 +638,7 @@ public final SSLEngineResult wrap(
bytesProduced += bioLengthBefore - pendingNow;
bioLengthBefore = pendingNow;

if (bytesConsumed == MAX_PLAINTEXT_LENGTH || bytesProduced == dst.remaining()) {
return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Scottmitch why is this not needed anymore ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is explained in the commit message:

OpenSslEngine#wrap should only produce a single TLS packet according to the SSLEngine API specificaiton [1].
[1] https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SSLEngine.html#wrap-java.nio.ByteBuffer:A-int-int-java.nio.ByteBuffer-

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we consume multiple packets we must be more careful about how much overhead we account for. This is done in PR #6365

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it... Sorry I missed this before.

@normanmaurer
Copy link
Member

@Scottmitch LGTM... please merge once the CI passes

@Scottmitch
Copy link
Member Author

3 minutes isn't enough on the CI servers ... bumping to 5 minutes.

Motivation:
SSL_write requires a fixed amount of bytes for overhead related to the encryption process for each call. OpenSslEngine#wrap(..) will attempt to encrypt multiple input buffers until MAX_PLAINTEXT_LENGTH are consumed, but the size estimation provided by calculateOutNetBufSize may not leave enough room for each call to SSL_write. If SSL_write is not able to completely write results to the destination buffer it will keep state and attempt to write it later. Netty doesn't account for SSL_write keeping state and assumes all writes will complete synchronously (by attempting to allocate enough space to account for the overhead) and feeds the same data to SSL_write again later which results in corrupted data being generated.

Modifications:
- OpenSslEngine#wrap should only produce a single TLS packet according to the SSLEngine API specificaiton [1].
[1] https://docs.oracle.com/javase/8/docs/api/javax/net/ssl/SSLEngine.html#wrap-java.nio.ByteBuffer:A-int-int-java.nio.ByteBuffer-
- OpenSslEngine#wrap should only consider a single buffer when determining if there is enough space to write, because only a single buffer will ever be consumed.

Result:
OpenSslEngine#wrap will no longer produce corrupted data due to incorrect accounting of space required in the destination buffers.
@Scottmitch
Copy link
Member Author

Note that performance may be impacted as a result of this PR (due to strictly limiting the amount of data encrypted per wrap call), but PR #6365 will improve upon the ability to wrap (and unwrap) multiple TLS packets per call.

@Scottmitch
Copy link
Member Author

4.1 (1410899) 4.0 (aef6dbc)

@Scottmitch Scottmitch closed this May 8, 2017
@Scottmitch Scottmitch deleted the openssl_multi_src_overhead branch May 8, 2017 22:04
@lukaszx0
Copy link
Contributor

grpc-java was failing when upgraded to 4.1.10.Final with netty-tcnative 2.0.1.Final (see #2973). I just tried the latest netty snapshots and it is passing now - thanks @Scottmitch !

For posterity, if you're app is failing with weird javax.net.ssl.SSLException: Unsupported record version Unknown-126.182 (whole stacktrace) upgrade to >4.1.11.Final should fix it (as it'll contain this PR)

@normanmaurer
Copy link
Member

@lukaszx0 thanks for reporting back.

@Scottmitch
Copy link
Member Author

@lukaszx0 - Thanks for confirming. We are aware of the implications of this issue and are in the process of generating a new release now. Standby.

slandelle added a commit to AsyncHttpClient/async-http-client that referenced this pull request May 12, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants