diff options
author | Boris Pismenny <borisp@mellanox.com> | 2017-06-01 09:25:47 +0300 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2018-12-07 11:25:45 +0000 |
commit | 50ec750567e056fcecff2344c2d9044d81cc731b (patch) | |
tree | c4da98b9c0a4fa6f528a74914fde3d21bc38b80a /ssl | |
parent | ecd1557fb4589103316c65b1fd1d4217a30900c0 (diff) |
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: Boris Pismenny <borisp@mellanox.com>
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Paul Yang <yang.yang@baishancloud.com>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/5253)
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/record/rec_layer_s3.c | 116 | ||||
-rw-r--r-- | ssl/record/record_locl.h | 1 | ||||
-rw-r--r-- | ssl/record/ssl3_buffer.c | 31 | ||||
-rw-r--r-- | ssl/ssl_lib.c | 29 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 1 | ||||
-rw-r--r-- | ssl/t1_enc.c | 71 |
6 files changed, 200 insertions, 49 deletions
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index 9ab370836e..2f5987b0e8 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -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; @@ -887,12 +905,16 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf, goto err; } } else { - if (!WPACKET_memcpy(thispkt, thiswr->input, thiswr->length)) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE, - ERR_R_INTERNAL_ERROR); - goto err; + 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, + ERR_R_INTERNAL_ERROR); + goto err; + } + SSL3_RECORD_reset_input(&wr[j]); } - SSL3_RECORD_reset_input(&wr[j]); } if (SSL_TREAT_AS_TLS13(s) @@ -967,24 +989,26 @@ 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, - NULL) - /* - * We also need next the amount of bytes written to this - * sub-packet - */ + 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 + * sub-packet + */ || !WPACKET_get_length(thispkt, &len)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR); goto err; - } - - /* 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); + /* 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,12 +1024,14 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf, goto err; } } else { - 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, - ERR_R_INTERNAL_ERROR); + 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, + ERR_R_INTERNAL_ERROR); + } + goto err; } - goto err; } } @@ -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]) diff --git a/ssl/record/record_locl.h b/ssl/record/record_locl.h index bf52ee1602..ed421881d8 100644 --- a/ssl/record/record_locl.h +++ b/ssl/record/record_locl.h @@ -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)) diff --git a/ssl/record/ssl3_buffer.c b/ssl/record/ssl3_buffer.c index 8960290e12..09cf587bf3 100644 --- a/ssl/record/ssl3_buffer.c +++ b/ssl/record/ssl3_buffer.c @@ -111,23 +111,27 @@ int ssl3_setup_write_buffer(SSL *s, size_t numwpipes, size_t len) for (currpipe = 0; currpipe < numwpipes; currpipe++) { SSL3_BUFFER *thiswb = &wb[currpipe]; - if (thiswb->buf != NULL && thiswb->len != len) { + if (thiswb->len != len) { OPENSSL_free(thiswb->buf); thiswb->buf = NULL; /* force reallocation */ } if (thiswb->buf == NULL) { - p = OPENSSL_malloc(len); - if (p == NULL) { - s->rlayer.numwpipes = currpipe; - /* - * We've got a malloc failure, and we're still initialising - * buffers. We assume we're so doomed that we won't even be able - * to send an alert. - */ - SSLfatal(s, SSL_AD_NO_ALERT, - SSL_F_SSL3_SETUP_WRITE_BUFFER, ERR_R_MALLOC_FAILURE); - return 0; + if (s->wbio == NULL || !BIO_get_ktls_send(s->wbio)) { + p = OPENSSL_malloc(len); + if (p == NULL) { + s->rlayer.numwpipes = currpipe; + /* + * We've got a malloc failure, and we're still initialising + * buffers. We assume we're so doomed that we won't even be able + * to send an alert. + */ + SSLfatal(s, SSL_AD_NO_ALERT, + SSL_F_SSL3_SETUP_WRITE_BUFFER, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + p = NULL; } memset(thiswb, 0, sizeof(SSL3_BUFFER)); thiswb->buf = p; @@ -160,7 +164,8 @@ int ssl3_release_write_buffer(SSL *s) while (pipes > 0) { wb = &RECORD_LAYER_get_wbuf(&s->rlayer)[pipes - 1]; - OPENSSL_free(wb->buf); + if (s->wbio == NULL || !BIO_get_ktls_send(s->wbio)) + OPENSSL_free(wb->buf); wb->buf = NULL; pipes--; } diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index a709792c21..ba606e35ed 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -22,6 +22,7 @@ #include <openssl/ct.h> #include "internal/cryptlib.h" #include "internal/refcount.h" +#include "internal/ktls.h" static int ssl_undefined_function_1(SSL *ssl, SSL3_RECORD *r, size_t s, int t) { @@ -1146,11 +1147,15 @@ void SSL_free(SSL *s) dane_final(&s->dane); CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data); + RECORD_LAYER_release(&s->rlayer); + /* Ignore return value */ ssl_free_wbio_buffer(s); BIO_free_all(s->wbio); + s->wbio = NULL; BIO_free_all(s->rbio); + s->rbio = NULL; BUF_MEM_free(s->init_buf); @@ -1201,8 +1206,6 @@ void SSL_free(SSL *s) if (s->method != NULL) s->method->ssl_free(s); - RECORD_LAYER_release(&s->rlayer); - SSL_CTX_free(s->ctx); ASYNC_WAIT_CTX_free(s->waitctx); @@ -1342,6 +1345,15 @@ int SSL_set_fd(SSL *s, int fd) } BIO_set_fd(bio, fd, BIO_NOCLOSE); SSL_set_bio(s, bio, bio); +#ifndef OPENSSL_NO_KTLS + /* + * The new socket is created successfully regardless of ktls_enable. + * ktls_enable doesn't change any functionality of the socket, except + * changing the setsockopt to enable the processing of ktls_start. + * Thus, it is not a problem to call it for non-TLS sockets. + */ + ktls_enable(fd); +#endif /* OPENSSL_NO_KTLS */ ret = 1; err: return ret; @@ -1361,6 +1373,15 @@ int SSL_set_wfd(SSL *s, int fd) } BIO_set_fd(bio, fd, BIO_NOCLOSE); SSL_set0_wbio(s, bio); +#ifndef OPENSSL_NO_KTLS + /* + * The new socket is created successfully regardless of ktls_enable. + * ktls_enable doesn't change any functionality of the socket, except + * changing the setsockopt to enable the processing of ktls_start. + * Thus, it is not a problem to call it for non-TLS sockets. + */ + ktls_enable(fd); +#endif /* OPENSSL_NO_KTLS */ } else { BIO_up_ref(rbio); SSL_set0_wbio(s, rbio); @@ -2186,6 +2207,10 @@ long SSL_ctrl(SSL *s, int cmd, long larg, void *parg) case SSL_CTRL_SET_MAX_SEND_FRAGMENT: if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH) return 0; +#ifndef OPENSSL_NO_KTLS + if (s->wbio != NULL && BIO_get_ktls_send(s->wbio)) + return 0; +#endif /* OPENSSL_NO_KTLS */ s->max_send_fragment = larg; if (s->max_send_fragment < s->split_send_fragment) s->split_send_fragment = s->max_send_fragment; diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 98e8e8a46d..c2e6474f86 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -34,6 +34,7 @@ # include "internal/dane.h" # include "internal/refcount.h" # include "internal/tsan_assist.h" +# include "internal/bio.h" # ifdef OPENSSL_BUILD_SHLIBSSL # undef OPENSSL_EXTERN diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index 2313afd3b7..adcc62619f 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -10,10 +10,14 @@ #include <stdio.h> #include "ssl_locl.h" +#include "record/record_locl.h" +#include "internal/ktls.h" +#include "internal/cryptlib.h" #include <openssl/comp.h> #include <openssl/evp.h> #include <openssl/kdf.h> #include <openssl/rand.h> +#include <openssl/obj_mac.h> /* seed1 through seed5 are concatenated */ static int tls1_PRF(SSL *s, @@ -98,6 +102,11 @@ int tls1_change_cipher_state(SSL *s, int which) EVP_PKEY *mac_key; size_t n, i, j, k, cl; int reuse_dd = 0; +#ifndef OPENSSL_NO_KTLS + struct tls12_crypto_info_aes_gcm_128 crypto_info; + BIO *wbio; + unsigned char geniv[12]; +#endif c = s->s3->tmp.new_sym_enc; m = s->s3->tmp.new_hash; @@ -319,6 +328,68 @@ int tls1_change_cipher_state(SSL *s, int which) ERR_R_INTERNAL_ERROR); goto err; } +#ifndef OPENSSL_NO_KTLS + if (s->compress) + goto skip_ktls; + + if ((which & SSL3_CC_READ) || + ((which & SSL3_CC_WRITE) && (s->mode & SSL_MODE_NO_KTLS_TX))) + goto skip_ktls; + + /* ktls supports only the maximum fragment size */ + if (ssl_get_max_send_fragment(s) != SSL3_RT_MAX_PLAIN_LENGTH) + goto skip_ktls; + + /* check that cipher is AES_GCM_128 */ + if (EVP_CIPHER_nid(c) != NID_aes_128_gcm + || EVP_CIPHER_mode(c) != EVP_CIPH_GCM_MODE + || EVP_CIPHER_key_length(c) != TLS_CIPHER_AES_GCM_128_KEY_SIZE) + goto skip_ktls; + + /* check version is 1.2 */ + if (s->version != TLS1_2_VERSION) + goto skip_ktls; + + wbio = s->wbio; + if (!ossl_assert(wbio != NULL)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS1_CHANGE_CIPHER_STATE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + /* All future data will get encrypted by ktls. Flush the BIO or skip ktls */ + if (BIO_flush(wbio) <= 0) + goto skip_ktls; + + /* ktls doesn't support renegotiation */ + if (BIO_get_ktls_send(s->wbio)) { + SSLfatal(s, SSL_AD_NO_RENEGOTIATION, SSL_F_TLS1_CHANGE_CIPHER_STATE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + memset(&crypto_info, 0, sizeof(crypto_info)); + crypto_info.info.cipher_type = TLS_CIPHER_AES_GCM_128; + crypto_info.info.version = s->version; + + EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_GET_IV, + EVP_GCM_TLS_FIXED_IV_LEN + EVP_GCM_TLS_EXPLICIT_IV_LEN, + geniv); + memcpy(crypto_info.iv, geniv + EVP_GCM_TLS_FIXED_IV_LEN, + TLS_CIPHER_AES_GCM_128_IV_SIZE); + memcpy(crypto_info.salt, geniv, TLS_CIPHER_AES_GCM_128_SALT_SIZE); + memcpy(crypto_info.key, key, EVP_CIPHER_key_length(c)); + memcpy(crypto_info.rec_seq, &s->rlayer.write_sequence, + TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE); + + /* ktls works with user provided buffers directly */ + if (BIO_set_ktls(wbio, &crypto_info, which & SSL3_CC_WRITE)) { + ssl3_release_write_buffer(s); + SSL_set_options(s, SSL_OP_NO_RENEGOTIATION); + } + + skip_ktls: +#endif /* OPENSSL_NO_KTLS */ s->statem.enc_write_state = ENC_WRITE_STATE_VALID; #ifdef SSL_DEBUG |