Commit 50ec7505 authored by Boris Pismenny's avatar Boris Pismenny Committed by Matt Caswell
Browse files

ssl: Linux TLS Tx Offload



This patch adds support for the Linux TLS Tx socket option.
If the socket option is successful, then the data-path of the TCP socket
is implemented by the kernel.
We choose to set this option at the earliest - just after CCS is complete.

Signed-off-by: default avatarBoris Pismenny <borisp@mellanox.com>

Reviewed-by: default avatarTim Hudson <tjh@openssl.org>
Reviewed-by: default avatarPaul Yang <yang.yang@baishancloud.com>
Reviewed-by: default avatarMatt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/5253)
parent ecd1557f
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
BIO_ctrl, BIO_callback_ctrl, BIO_ptr_ctrl, BIO_int_ctrl, BIO_reset,
BIO_seek, BIO_tell, BIO_flush, BIO_eof, BIO_set_close, BIO_get_close,
BIO_pending, BIO_wpending, BIO_ctrl_pending, BIO_ctrl_wpending,
BIO_get_info_callback, BIO_set_info_callback, BIO_info_cb
BIO_get_info_callback, BIO_set_info_callback, BIO_info_cb, BIO_get_ktls_send
- BIO control operations

=head1 SYNOPSIS
@@ -34,6 +34,8 @@ BIO_get_info_callback, BIO_set_info_callback, BIO_info_cb
 int BIO_get_info_callback(BIO *b, BIO_info_cb **cbp);
 int BIO_set_info_callback(BIO *b, BIO_info_cb *cb);

 int BIO_get_ktls_send(BIO *b);

=head1 DESCRIPTION

BIO_ctrl(), BIO_callback_ctrl(), BIO_ptr_ctrl() and BIO_int_ctrl()
@@ -72,6 +74,9 @@ Not all BIOs support these calls. BIO_ctrl_pending() and BIO_ctrl_wpending()
return a size_t type and are functions, BIO_pending() and BIO_wpending() are
macros which call BIO_ctrl().

BIO_get_ktls_send() return 1 if the BIO is using the Kernel TLS data-path for
sending. Otherwise, it returns zero.

=head1 RETURN VALUES

BIO_reset() normally returns 1 for success and 0 or -1 for failure. File
@@ -92,6 +97,9 @@ BIO_get_close() returns the close flag value: BIO_CLOSE or BIO_NOCLOSE.
BIO_pending(), BIO_ctrl_pending(), BIO_wpending() and BIO_ctrl_wpending()
return the amount of pending data.

BIO_get_ktls_send() return 1 if the BIO is using the Kernel TLS data-path for
sending. Otherwise, it returns zero.

=head1 NOTES

BIO_flush(), because it can write data may return 0 or -1 indicating
@@ -124,6 +132,10 @@ particular a return value of 0 can be returned if an operation is not
supported, if an error occurred, if EOF has not been reached and in
the case of BIO_seek() on a file BIO for a successful operation.

=head1 HISTORY

The BIO_get_ktls_send() function was added in OpenSSL 3.0.0.

=head1 COPYRIGHT

Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
+17 −0
Original line number Diff line number Diff line
@@ -105,6 +105,22 @@ Enable asynchronous processing. TLS I/O operations may indicate a retry with
SSL_ERROR_WANT_ASYNC with this mode set if an asynchronous capable engine is
used to perform cryptographic operations. See L<SSL_get_error(3)>.

=item SSL_MODE_NO_KTLS_TX

Disable the use of the kernel TLS egress data-path.
By default kernel TLS is enabled if it is supported by the negotiated ciphersuites
and extensions and OpenSSL has been compiled with support for it.
The kernel TLS data-path implements the record layer,
and the crypto algorithm. The kernel will utilize the best hardware
available for crypto. Using the kernel data-path should reduce the memory
footprint of OpenSSL because no buffering is required. Also, the throughput
should improve because data copy is avoided when user data is encrypted into
kernel memory instead of the usual encrypt than copy to kernel.

Kernel TLS might not support all the features of OpenSSL. For instance,
renegotiation, and setting the maximum fragment size is not possible as of
Linux 4.20.

=back

All modes are off by default except for SSL_MODE_AUTO_RETRY which is on by
@@ -125,6 +141,7 @@ L<SSL_write(3)>, L<SSL_get_error(3)>
=head1 HISTORY

SSL_MODE_ASYNC was first added to OpenSSL 1.1.0.
SSL_MODE_NO_KTLS_TX was first added to OpenSSL 3.0.0.

=head1 COPYRIGHT

+4 −0
Original line number Diff line number Diff line
@@ -493,6 +493,10 @@ typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);
 * Support Asynchronous operation
 */
# define SSL_MODE_ASYNC 0x00000100U
/*
 * Use the kernel TLS transmission data-path.
 */
# define SSL_MODE_NO_KTLS_TX 0x00000200U

/* Cert related flags */
/*
+82 −34
Original line number Diff line number Diff line
@@ -743,6 +743,18 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
        s->s3->empty_fragment_done = 1;
    }

    if (BIO_get_ktls_send(s->wbio)) {
        /*
         * ktls doesn't modify the buffer, but to avoid a warning we need to
         * discard the const qualifier.
         * This doesn't leak memory because the buffers have been released when
         * switching to ktls.
         */
        SSL3_BUFFER_set_buf(&s->rlayer.wbuf[0], (unsigned char *)buf);
        SSL3_BUFFER_set_offset(&s->rlayer.wbuf[0], 0);
        goto wpacket_init_complete;
    }

    if (create_empty_fragment) {
        wb = &s->rlayer.wbuf[0];
#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0
@@ -812,6 +824,8 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
        }
    }

 wpacket_init_complete:

    totlen = 0;
    /* Clear our SSL3_RECORD structures */
    memset(wr, 0, sizeof(wr));
@@ -853,15 +867,19 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
        if (s->compress != NULL)
            maxcomplen += SSL3_RT_MAX_COMPRESSED_OVERHEAD;

        /* write the header */
        if (!WPACKET_put_bytes_u8(thispkt, rectype)
        /*
         * When using offload kernel will write the header.
         * Otherwise write the header now
         */
        if (!BIO_get_ktls_send(s->wbio)
                && (!WPACKET_put_bytes_u8(thispkt, rectype)
                || !WPACKET_put_bytes_u16(thispkt, version)
                || !WPACKET_start_sub_packet_u16(thispkt)
                || (eivlen > 0
                    && !WPACKET_allocate_bytes(thispkt, eivlen, NULL))
                || (maxcomplen > 0
                    && !WPACKET_reserve_bytes(thispkt, maxcomplen,
                                              &compressdata))) {
                                              &compressdata)))) {
            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
                     ERR_R_INTERNAL_ERROR);
            goto err;
@@ -886,6 +904,9 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
                         SSL_R_COMPRESSION_FAILURE);
                goto err;
            }
        } else {
            if (BIO_get_ktls_send(s->wbio)) {
                SSL3_RECORD_reset_data(&wr[j]);
            } else {
                if (!WPACKET_memcpy(thispkt, thiswr->input, thiswr->length)) {
                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
@@ -894,6 +915,7 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
                }
                SSL3_RECORD_reset_input(&wr[j]);
            }
        }

        if (SSL_TREAT_AS_TLS13(s)
                && s->enc_write_ctx != NULL
@@ -967,7 +989,9 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
         * This will be at most one cipher block or the tag length if using
         * AEAD. SSL_RT_MAX_CIPHER_BLOCK_SIZE covers either case.
         */
        if (!WPACKET_reserve_bytes(thispkt, SSL_RT_MAX_CIPHER_BLOCK_SIZE,
        if (!BIO_get_ktls_send(s->wbio)) {
            if (!WPACKET_reserve_bytes(thispkt,
                                        SSL_RT_MAX_CIPHER_BLOCK_SIZE,
                                        NULL)
                /*
                 * We also need next the amount of bytes written to this
@@ -981,11 +1005,11 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,

            /* Get a pointer to the start of this record excluding header */
            recordstart = WPACKET_get_curr(thispkt) - len;

            SSL3_RECORD_set_data(thiswr, recordstart);
            SSL3_RECORD_reset_input(thiswr);
            SSL3_RECORD_set_length(thiswr, len);
        }
    }

    if (s->statem.enc_write_state == ENC_WRITE_STATE_WRITE_PLAIN_ALERTS) {
        /*
@@ -1000,6 +1024,7 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
            goto err;
        }
    } else {
        if (!BIO_get_ktls_send(s->wbio)) {
            if (s->method->ssl3_enc->enc(s, wr, numpipes, 1) < 1) {
                if (!ossl_statem_in_error(s)) {
                    SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
@@ -1008,6 +1033,7 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
                goto err;
            }
        }
    }

    for (j = 0; j < numpipes; j++) {
        size_t origlen;
@@ -1015,13 +1041,17 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
        thispkt = &pkt[j];
        thiswr = &wr[j];

        if (BIO_get_ktls_send(s->wbio))
            goto mac_done;

        /* Allocate bytes for the encryption overhead */
        if (!WPACKET_get_length(thispkt, &origlen)
                   /* Encryption should never shrink the data! */
                || origlen > thiswr->length
                || (thiswr->length > origlen
                    && !WPACKET_allocate_bytes(thispkt,
                                               thiswr->length - origlen, NULL))) {
                                               thiswr->length - origlen,
                                               NULL))) {
            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE,
                     ERR_R_INTERNAL_ERROR);
            goto err;
@@ -1066,13 +1096,8 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
            goto err;
        }

        /*
         * we should now have thiswr->data pointing to the encrypted data, which
         * is thiswr->length long
         */
        SSL3_RECORD_set_type(thiswr, type); /* not needed but helps for
                                             * debugging */
        SSL3_RECORD_add_length(thiswr, SSL3_RT_HEADER_LENGTH);
        /* header is added by the kernel when using offload */
        SSL3_RECORD_add_length(&wr[j], SSL3_RT_HEADER_LENGTH);

        if (create_empty_fragment) {
            /*
@@ -1089,6 +1114,14 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
            return 1;
        }

 mac_done:
        /*
         * we should now have thiswr->data pointing to the encrypted data, which
         * is thiswr->length long
         */
        SSL3_RECORD_set_type(thiswr, type); /* not needed but helps for
                                             * debugging */

        /* now let's set up wb */
        SSL3_BUFFER_set_left(&s->rlayer.wbuf[j],
                             prefix_len + SSL3_RECORD_get_length(thiswr));
@@ -1142,6 +1175,21 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, size_t len,
        clear_sys_error();
        if (s->wbio != NULL) {
            s->rwstate = SSL_WRITING;

            /*
             * To prevent coalescing of control and data messages,
             * such as in buffer_write, we flush the BIO
             */
            if (BIO_get_ktls_send(s->wbio) && type != SSL3_RT_APPLICATION_DATA) {
                i = BIO_flush(s->wbio);
                if (i <= 0)
                    return i;
            }

            if (BIO_get_ktls_send(s->wbio)
                && type != SSL3_RT_APPLICATION_DATA) {
                BIO_set_ktls_ctrl_msg(s->wbio, type);
            }
            /* TODO(size_t): Convert this call */
            i = BIO_write(s->wbio, (char *)
                          &(SSL3_BUFFER_get_buf(&wb[currbuf])
+1 −0
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ int ssl3_release_write_buffer(SSL *s);
#define SSL3_RECORD_get_input(r)                ((r)->input)
#define SSL3_RECORD_set_input(r, i)             ((r)->input = (i))
#define SSL3_RECORD_reset_input(r)              ((r)->input = (r)->data)
#define SSL3_RECORD_reset_data(r)               ((r)->data = (r)->input)
#define SSL3_RECORD_get_seq_num(r)              ((r)->seq_num)
#define SSL3_RECORD_get_off(r)                  ((r)->off)
#define SSL3_RECORD_set_off(r, o)               ((r)->off = (o))
Loading