-
-
Notifications
You must be signed in to change notification settings - Fork 15.8k
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
SslHandler and OpenSslEngine miscalculation of wrap destination buffe… #6492
Conversation
|
||
private void compositeBufSizeEstimationGuaranteesSynchronousWrite(SslProvider serverProvider, | ||
SslProvider clientProvider) | ||
throws CertificateException, SSLException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
formatting looks strange
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how would you prefer this be formatted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private void compositeBufSizeEstimationGuaranteesSynchronousWrite(
SslProvider serverProvider, SslProvider clientProvider) throws CertificateException, SSLException {
Something like this maybe ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
d750e50
to
05df78b
Compare
group.shutdownGracefully(); | ||
|
||
ReferenceCountUtil.release(sslServerCtx); | ||
ReferenceCountUtil.release(sslClientCtx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
call ssc.delete();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -107,11 +107,12 @@ | |||
* allow up to 255 bytes. 16 bytes is the max for PKC#5 (which handles it the same way as PKC#7) as we use a block | |||
* size of 16. See <a href="https://tools.ietf.org/html/rfc5652#section-6.3">rfc5652#section-6.3</a>. | |||
* | |||
* 16 (IV) + 48 (MAC) + 1 (Padding_length field) + 15 (Padding) + 1 (ContentType) + 2 (ProtocolVersion) + 2 (Length) | |||
* 5 (TLS Header) + 16 (IV) + 48 (MAC) + 1 (Padding_length field) + 15 (Padding) + 1 (ContentType) + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we missed the 5 bytes ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes
static int calculateOutNetBufSize(int pendingBytes) { | ||
return min(MAX_ENCRYPTED_PACKET_LENGTH, MAX_ENCRYPTION_OVERHEAD_LENGTH | ||
static int calculateOutNetBufSize(int pendingBytes, int numComponents) { | ||
return min(MAX_ENCRYPTED_PACKET_LENGTH, MAX_ENCRYPTION_OVERHEAD_LENGTH * numComponents |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need to multiply this by the number of components ? Shouldn't it not matter as we only need to worry about the summary of the readable bytes of all of them as we can only create one record with all of the components in it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is described in the commit message but if we have a CompositeByteBuf
we break that down into ByteBuffer[]
and call SSL_write
for each of these. So each ByteBuffer
will incur the tls record overhead. I wanted to review this more because it may be the case that we can apply the encryption overhead to all the bytes, and other apply the tls record overhead (header) for each ByteBuffer
. I think this case ... so let me refine this estimate.
@@ -560,4 +564,127 @@ public void operationComplete(Future<Channel> future) { | |||
ReferenceCountUtil.release(sslClientCtx); | |||
} | |||
} | |||
|
|||
@Test(timeout = 30000) | |||
public void testCompositeBufSizeEstimationGuaranteesSynchronousWrite() throws CertificateException, SSLException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also would be nice if we had this as test that not depends on the SslHandler
but only uses the SSLEngine itself
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SslHandler is involved in the estimation process so it has a role to play in this failure.
@normanmaurer - PTAL |
return min(MAX_ENCRYPTED_PACKET_LENGTH, MAX_ENCRYPTION_OVERHEAD_LENGTH | ||
+ min(MAX_ENCRYPTION_OVERHEAD_DIFF, pendingBytes)); | ||
static int calculateOutNetBufSize(int pendingBytes, int numComponents) { | ||
int amt = pendingBytes + MAX_TLS_RECORD_OVERHEAD_LENGTH * numComponents; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@normanmaurer - I consulted with @davidben regarding the question in #6492 (comment) ... each call to SSL_write
should account for the encryption overhead + tls header length
amount of overhead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is Integer.MAX_VALUE safe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Scottmitch ok thanks for verify
return TCNATIVE; | ||
} | ||
return JDK; | ||
return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE : JDK; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JDK SslEngine when using OpenSslEngine and finalizer? 😕 Shouldn't this instance of check remain OpenSslEngine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JDK SslEngine when using OpenSslEngine and finalizer?
I don't understand this statement. Can you explain.
Basically ReferenceCountedOpenSslEngine
is the base class of OpenSslEngine
and is the class which provides the interface which SslEngineType#TCNATIVE
depends upon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eugh, I had it in my head that ReferenceCountedOpenSslEngine extends OpenSslEngine.
@@ -193,7 +193,7 @@ SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, | |||
* we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method | |||
* that accepts multiple {@link ByteBuffer}s without additional memory copies. | |||
*/ | |||
OpenSslEngine opensslEngine = (OpenSslEngine) handler.engine; | |||
ReferenceCountedOpenSslEngine opensslEngine = (ReferenceCountedOpenSslEngine) handler.engine; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
classcastexception when using openssl with finalizer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. ReferenceCountedOpenSslEngine
is the base class of OpenSslEngine
.
…r size Motivation: When we do a wrap operation we calculate the maximum size of the destination buffer ahead of time, and return a BUFFER_OVERFLOW exception if the destination buffer is not big enough. However if there is a CompositeByteBuf the wrap operation may consist of multiple ByteBuffers and each incurs its own overhead during the encryption. We currently don't account for the overhead required for encryption if there are multiple ByteBuffers and we assume the overhead will only apply once to the entire input size. If there is not enough room to write an entire encrypted packed into the BIO SSL_write will return -1 despite having actually written content to the BIO. We then attempt to retry the write with a bigger buffer, but because SSL_write is stateful the remaining bytes from the previous operation are put into the BIO. This results in sending the second half of the encrypted data being sent to the peer which is not of proper format and the peer will be confused and ultimately not get the expected data (which may result in a fatal error). In this case because SSL_write returns -1 we have no way to know how many bytes were actually consumed and so the best we can do is ensure that we always allocate a destination buffer with enough space so we are guaranteed to complete the write operation synchronously. Modifications: - SslHandler#allocateNetBuf should take into account how many ByteBuffers will be wrapped and apply the encryption overhead for each - Include the TLS header length in the overhead computation Result: Fixes netty#6481
…r size
Motivation:
When we do a wrap operation we calculate the maximum size of the destination buffer ahead of time, and return a BUFFER_OVERFLOW exception if the destination buffer is not big enough. However if there is a CompositeByteBuf the wrap operation may consist of multiple ByteBuffers and each incurs its own overhead during the encryption. We currently don't account for the overhead required for encryption if there are multiple ByteBuffers and we assume the overhead will only apply once to the entire input size. If there is not enough room to write an entire encrypted packed into the BIO SSL_write will return -1 despite having actually written content to the BIO. We then attempt to retry the write with a bigger buffer, but because SSL_write is stateful the remaining bytes from the previous operation are put into the BIO. This results in sending the second half of the encrypted data being sent to the peer which is not of proper format and the peer will be confused and ultimately not get the expected data (which may result in a fatal error). In this case because SSL_write returns -1 we have no way to know how many bytes were actually consumed and so the best we can do is ensure that we always allocate a destination buffer with enough space so we are guaranteed to complete the write operation synchronously.
Modifications:
Result:
Fixes #6481