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
KTLS: Enable KTLS for receiving as well in TLS 1.3 #16798
Conversation
This adds a couple of special cases in ssl3_get_record() for KTLS: first, record unpadding is handled by the kernel and the type and length fields of the received SSL3_RECORD should have the correct value; secondly, the record type check for TLS 1.3 records is not relevant in KTLS, as the kernel provides unprotected record content. Signed-off-by: Daiki Ueno <dueno@redhat.com>
This removes a guard condition that prevents KTLS being enabled for receiving in TLS 1.3. Signed-off-by: Daiki Ueno <dueno@redhat.com>
3bd87a7
to
e2dd40e
Compare
Hmm, in the TLS < 1.3 case, there is an additional check to ensure that there aren't partially-received TLS records in the read-ahead cache of the read BIO. This is used to update the sequence number provided to the kernel as well as to reject KTLS if the read-ahead cache contains partially-read (vs complete) TLS records. I don't see a similar check here, so how are you handling that edge case? (For the < 1.3 case see the code to use count_unprocessed_records in t1_enc.c). For the tests, I also wonder if we want a OPENSSL_NO_KTLS_RX_13 or not. I'd mostly like to avoid adding more mazes of #ifdef's in the tests, but we'd need to make the tests not consider it a failure if a given (cipher suite, direction) tuple fails to offload to avoid false negatives on older kernels. |
if (SSL_IS_TLS13(s) && s->enc_read_ctx != NULL) { | ||
if (SSL_IS_TLS13(s) | ||
&& s->enc_read_ctx != NULL | ||
&& !BIO_get_ktls_recv(s->rbio)) { | ||
if (thisrr->type != SSL3_RT_APPLICATION_DATA | ||
&& (thisrr->type != SSL3_RT_CHANGE_CIPHER_SPEC | ||
|| !SSL_IS_FIRST_HANDSHAKE(s)) |
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.
GitHub's UI won't let me add this on the correct line, but I believe that for KTLS we should adjust the TLS1.3 specific check below on like 396 as for KTLS the extra byte for the record length has been stripped and the length should be validated against SSL3_RT_MAX_ENCRYPTED_LENGTH instead?
|
||
thisrr->length = end; | ||
thisrr->type = thisrr->data[end]; | ||
if (thisrr->type != SSL3_RT_APPLICATION_DATA |
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.
Do we still wish to do this check of the "real" record type even in the KTLS case? In my WIP for FreeBSD KTLS while I validate the outer record type, I am currently just returning the inner record type without performing additional checks on the type in the kernel. Does Linux perform validation of the inner record type in the kernel?
} | ||
if (s->msg_callback) | ||
s->msg_callback(0, s->version, SSL3_RT_INNER_CONTENT_TYPE, | ||
&thisrr->data[end], 1, s, s->msg_callback_arg); | ||
&thisrr->data[thisrr->length], 1, s, |
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 this correct for KTLS? AFAIU, &thisrr->data[thisrr->length]
won't contain the inner type.
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 agree with @pasis. It should probably be &thisrr->type
which will work for both KTLS and non-KTLS as the non-KTLS case has already updated thisrr->type
at this point.
@@ -723,8 +722,10 @@ int tls13_change_cipher_state(SSL *s, int which) | |||
goto skip_ktls; |
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.
if (which & SSL3_CC_WRITE)
rl_sequence = RECORD_LAYER_get_write_sequence(&s->rlayer);
else
rl_sequence = RECORD_LAYER_get_read_sequence(&s->rlayer);
if (!ktls_configure_crypto(s, cipher, ciph_ctx, r1_sequence,
&crypto_info, NULL, iv, key, NULL, 0))
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 agree with @yangyangtiantianlonglong's suggestion.
Lines 480 to 498 in 065121f
If read_ahead is set for receiving in TLS 1.3. The unprocess record needs to be performed ? |
I think so? That is what I was asking about earlier in my first comment. I guess I should see if this edge case can be provoked via a small test case. |
I've pushed a branch with fixes for the various issues here along with some other bugs I noticed (e.g. not using the right bio for RX) here: master...bsdjhb:ktls_rx_tls13 The history of that branch would probably need to be squashed a bit to be a better commit candidate. |
@bsdjhb, both original PR and your branch have an issue when I get this scenario in the most runs of NGINX with WRK benchmark. It's enough to run WRK with a single thread and single connection to reproduce. It looks like for TLS1.3 openssl doesn't handle encrypted records that are received before KTLS configuration is finished. Unfortunately I don't have enough expertise to find the root cause. |
Hmm, I had tested my branch with nginx and had some extra syslog messages in place to log that I was hitting the count > 0 case. I might not have checked the nginx logs for errors though, just that the client (openssl s_time) wasn't reporting errors. I will check this some more on my end. |
Main root cause is that unprocessed records (which are encrypted and in TLS1.3 format) are treated as TLS1.2 format due to insufficient condition. Check this diff: diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index b92b74c5f5..6b30d5eb66 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -687,7 +691,7 @@ int ssl3_get_record(SSL *s)
* content type, and padding is already removed and thisrr->type and
* thisrr->length should have the correct values.
*/
- if (!BIO_get_ktls_recv(s->rbio)) {
+ if (!BIO_get_ktls_recv(s->rbio) || is_ktls_left) {
size_t end;
if (thisrr->length == 0 Unprocessed records are in |
With the above patch I don't see issues in NGINX scenario so far. @bsdjhb please apply it to your branch. |
@pasis thanks for tracking that down. I had reproduced the error on Friday but hadn't debugged it yet. I found some other places that also needed to be checking |
Closing as superceeded by #17942 |
This series removes the restriction of not enabling KTLS for receiving in TLS 1.3. Some adjustments to
ssl3_get_record
are needed to handle unprotected records provided by the kernel properly.Checklist