This patch adds support for Linux TLS Tx offload. The data-path of the TLS socket is offloaded to the kernel after CCS is complete.
Change-Id: Ia966192a6704d1a57b74b2640ac04d55fb74c1c7 Signed-off-by: Boris Pismenny <bor...@mellanox.com> --- ssl/record/rec_layer_s3.c | 95 ++++++++++++++++++++++++++++++++++------------- ssl/t1_enc.c | 69 ++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 25 deletions(-) diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index 46870c0..a36be02 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -750,24 +750,31 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf, /* Clear our SSL3_RECORD structures */ memset(wr, 0, sizeof wr); for (j = 0; j < numpipes; j++) { - /* write the header */ - *(outbuf[j]++) = type & 0xff; - SSL3_RECORD_set_type(&wr[j], type); + if (BIO_get_offload_tx(s->wbio)) { + /* IV will be generated by the kernel if offload is used */ + eivlen = 0; - *(outbuf[j]++) = (s->version >> 8); - /* - * Some servers hang if initial client hello is larger than 256 bytes - * and record version number > TLS 1.0 - */ - if (SSL_get_state(s) == TLS_ST_CW_CLNT_HELLO - && !s->renegotiate && TLS1_get_version(s) > TLS1_VERSION) - *(outbuf[j]++) = 0x1; - else - *(outbuf[j]++) = s->version & 0xff; + SSL3_RECORD_set_type(&wr[j], type); + } else { + /* write the header */ + *(outbuf[j]++) = type & 0xff; + SSL3_RECORD_set_type(&wr[j], type); - /* field where we are to write out packet length */ - plen[j] = outbuf[j]; - outbuf[j] += 2; + *(outbuf[j]++) = (s->version >> 8); + /* + * Some servers hang if initial client hello is larger + * than 256 bytes and record version number > TLS 1.0 + */ + if (SSL_get_state(s) == TLS_ST_CW_CLNT_HELLO + && !s->renegotiate && TLS1_get_version(s) > TLS1_VERSION) + *(outbuf[j]++) = 0x1; + else + *(outbuf[j]++) = s->version & 0xff; + + /* field where we are to write out packet length */ + plen[j] = outbuf[j]; + outbuf[j] += 2; + } /* lets setup the record stuff. */ SSL3_RECORD_set_data(&wr[j], outbuf[j] + eivlen); @@ -815,8 +822,13 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf, } } - if (s->method->ssl3_enc->enc(s, wr, numpipes, 1) < 1) - goto err; + /* record sequence number is incremented inside ssl3_enc->enc() */ + if (!BIO_get_offload_tx(s->wbio)) { + if (s->method->ssl3_enc->enc(s, wr, numpipes, 1) < 1) { + goto err; + } + } + for (j = 0; j < numpipes; j++) { if (SSL_USE_ETM(s) && mac_size != 0) { @@ -826,12 +838,30 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf, SSL3_RECORD_add_length(&wr[j], mac_size); } - /* record length after mac and block padding */ - s2n(SSL3_RECORD_get_length(&wr[j]), plen[j]); - - if (s->msg_callback) - s->msg_callback(1, 0, SSL3_RT_HEADER, plen[j] - 5, 5, s, - s->msg_callback_arg); + if (!BIO_get_offload_tx(s->wbio)) { + /* record length after mac and block padding */ + s2n(SSL3_RECORD_get_length(&wr[j]), plen[j]); + if (s->msg_callback) + s->msg_callback(1, 0, SSL3_RT_HEADER, plen[j] - 5, 5, s, + s->msg_callback_arg); + } else { + /* Create a fake SSL3_RT_HEADER msg to maintain compatibility */ + if (s->msg_callback) { + unsigned char header[5] = {0}, *pheader = header + 3; + + header[0] = type & 0xff; + header[1] = (s->version >> 8); + if (SSL_get_state(s) == TLS_ST_CW_CLNT_HELLO + && !s->renegotiate + && TLS1_get_version(s) > TLS1_VERSION) + header[2] = 0x1; + else + header[2] = s->version & 0xff; + s2n(SSL3_RECORD_get_length(&wr[j]), pheader); + s->msg_callback(1, 0, SSL3_RT_HEADER, header, 5, s, + s->msg_callback_arg); + } + } /* * we should now have wr->data pointing to the encrypted data, which is @@ -839,7 +869,11 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf, */ SSL3_RECORD_set_type(&wr[j], type); /* not needed but helps for * debugging */ - SSL3_RECORD_add_length(&wr[j], SSL3_RT_HEADER_LENGTH); + + /* No header when using offload */ + if (!BIO_get_offload_tx(s->wbio)) { + SSL3_RECORD_add_length(&wr[j], SSL3_RT_HEADER_LENGTH); + } if (create_empty_fragment) { /* @@ -901,10 +935,21 @@ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, clear_sys_error(); if (s->wbio != NULL) { s->rwstate = SSL_WRITING; + if (BIO_get_offload_tx(s->wbio) && type != + SSL3_RT_APPLICATION_DATA) { + BIO_set_offload_tx_ctrl_msg(s->wbio, type); + } i = BIO_write(s->wbio, (char *) &(SSL3_BUFFER_get_buf(&wb[currbuf]) [SSL3_BUFFER_get_offset(&wb[currbuf])]), (unsigned int)SSL3_BUFFER_get_left(&wb[currbuf])); + /* To prevent coalescing of control and data messages, + * such as in buffer_write, we flush the BIO + */ + if (BIO_get_offload_tx(s->wbio) && + type != SSL3_RT_APPLICATION_DATA) { + (void)BIO_flush(s->wbio); + } } else { SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BIO_NOT_SET); i = -1; diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index 4aa5ddd..6b85c5c 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -41,6 +41,10 @@ #include <openssl/kdf.h> #include <openssl/rand.h> +#ifdef OPENSSL_LINUX_TLS +# include "netinet/tcp.h" // Add TLS stuff here.. +#endif + /* seed1 through seed5 are concatenated */ static int tls1_PRF(SSL *s, const void *seed1, int seed1_len, @@ -121,6 +125,11 @@ int tls1_change_cipher_state(SSL *s, int which) EVP_PKEY *mac_key; int n, i, j, k, cl; int reuse_dd = 0; +#ifdef OPENSSL_LINUX_TLS + 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; @@ -303,6 +312,66 @@ int tls1_change_cipher_state(SSL *s, int which) SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR); goto err2; } + +#ifdef OPENSSL_LINUX_TLS + if (!(which & SSL3_CC_WRITE)) { +#ifdef SSL_DEBUG + printf("\nSkipping offload for non-write context\n"); +#endif // SSL_DEBUG + goto skip_offload; + } + memset(&crypto_info, 0, sizeof(crypto_info)); + + /* check that cipher is AES_GCM_128 */ + if (EVP_CIPHER_mode(c) != EVP_CIPH_GCM_MODE) { +#ifdef SSL_DEBUG + printf("\nGot mode %08lx != GCM, skipping offload\n", + EVP_CIPHER_mode(c)); +#endif // SSL_DEBUG + goto skip_offload; + } + crypto_info.info.cipher_type = TLS_CIPHER_AES_GCM_128; + + /* check version is 1.2 */ + if (s->version != TLS1_2_VERSION) { +#ifdef SSL_DEBUG + printf("\nVersion mismatch got %08x, skipping offload\n", s->version); +#endif // SSL_DEBUG + goto skip_offload; + } + + if (EVP_CIPHER_key_length(c) != TLS_CIPHER_AES_GCM_128_KEY_SIZE) { +#ifdef SSL_DEBUG + printf("\nUnexpected key length %d, skipping offload\n", + EVP_CIPHER_key_length(c)); +#endif // SSL_DEBUG + goto skip_offload; + } + + crypto_info.info.version = s->version; + + /* This is not the IV that is used by OpenSSL, but rather the sequence + * number. We should actually provide both iv and sequence. + */ + EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_GCM_GET_IV, 12, geniv); + memcpy(crypto_info.iv, geniv + 4, 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); + + wbio = s->wbio; + if (!wbio) { + goto skip_offload; + } + + (void)BIO_flush(wbio); + + BIO_set_offload_tx(wbio, &crypto_info); + +skip_offload: +#endif // OPENSSL_LINUX_TLS + #ifdef OPENSSL_SSL_TRACE_CRYPTO if (s->msg_callback) { int wh = which & SSL3_CC_WRITE ? TLS1_RT_CRYPTO_WRITE : 0; -- 1.8.3.1 -- openssl-dev mailing list To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-dev