From 4935d50a97f7391795b7974b40c85003189f117a Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Thu, 17 May 2018 22:13:55 +0200 Subject: [PATCH] Enable RX support for kTLS. This bumps the TLS requirement to >= 4.17 (tested with 4.17.0-rc4), and doesn't really help all that much (neither in performance nor complexity), but there's no point in supporting a separate non-RX-capable path for 4.13 through 4.16. Includes updating tlse.c to the latest version. --- cubemap.config.sample | 4 ++-- server.cpp | 44 ++++++++++++++++++++++--------------------- server.h | 2 +- tlse/ktls.h | 1 + tlse/tlse.c | 30 ++++++++++++++++++++++++++++- 5 files changed, 56 insertions(+), 25 deletions(-) diff --git a/cubemap.config.sample b/cubemap.config.sample index e7119ff..51c46d3 100644 --- a/cubemap.config.sample +++ b/cubemap.config.sample @@ -11,8 +11,8 @@ num_servers 1 # # You may specify multiple input ports; save for TLS settings (TLS is automatically # enabled for a port if you give a key pair), they are treated exactly the same. -# “port N” is equivalent to “listen [::]:N”. TLS requires kTLS support (Linux >= 4.13, -# CONFIG_TLS enabled). +# “port N” is equivalent to “listen [::]:N”. TLS requires kTLS support with both +# RX and TX (Linux >= 4.17, CONFIG_TLS enabled). # port 9094 # listen 127.0.0.1:9095 diff --git a/server.cpp b/server.cpp index c12bc8d..61bdb3f 100644 --- a/server.cpp +++ b/server.cpp @@ -525,7 +525,7 @@ void Server::process_client(Client *client) { switch (client->state) { case Client::READING_REQUEST: { - if (client->tls_context != nullptr) { + if (client->tls_context != nullptr && !client->in_ktls_mode) { if (send_pending_tls_data(client)) { // send_pending_tls_data() hit postconditions #1 or #4. return; @@ -536,10 +536,10 @@ read_request_again: // Try to read more of the request. char buf[1024]; int ret; - if (client->tls_context == nullptr) { - ret = read_nontls_data(client, buf, sizeof(buf)); + if (client->tls_context == nullptr || client->in_ktls_mode) { + ret = read_plain_data(client, buf, sizeof(buf)); if (ret == -1) { - // read_nontls_data() hit postconditions #1 or #2. + // read_plain_data() hit postconditions #1 or #2. return; } } else { @@ -571,22 +571,6 @@ read_request_again: assert(status == RP_FINISHED); - if (client->tls_context && !client->in_ktls_mode && tls_established(client->tls_context)) { - // We're ready to enter kTLS mode, unless we still have some - // handshake data to send (which then must be sent as non-kTLS). - if (send_pending_tls_data(client)) { - // send_pending_tls_data() hit postconditions #1 or #4. - return; - } - ret = tls_make_ktls(client->tls_context, client->sock); - if (ret < 0) { - log_tls_error("tls_make_ktls", ret); - close_client(client); - return; - } - client->in_ktls_mode = true; - } - int error_code = parse_request(client); if (error_code == 200) { if (client->serving_hls_playlist) { @@ -886,7 +870,7 @@ send_data_again: goto send_data_again; } -int Server::read_nontls_data(Client *client, char *buf, size_t max_size) +int Server::read_plain_data(Client *client, char *buf, size_t max_size) { int ret; do { @@ -915,6 +899,8 @@ int Server::read_nontls_data(Client *client, char *buf, size_t max_size) int Server::read_tls_data(Client *client, char *buf, size_t max_size) { read_again: + assert(!client->in_ktls_mode); + int ret; do { ret = read(client->sock, buf, max_size); @@ -965,6 +951,22 @@ read_again: return -1; } + if (tls_established(client->tls_context)) { + // We're ready to enter kTLS mode, unless we still have some + // handshake data to send (which then must be sent as non-kTLS). + if (send_pending_tls_data(client)) { + // send_pending_tls_data() hit postconditions #1 or #4. + return -1; + } + int err = tls_make_ktls(client->tls_context, client->sock); // Don't overwrite ret. + if (err < 0) { + log_tls_error("tls_make_ktls", ret); + close_client(client); + return -1; + } + client->in_ktls_mode = true; + } + assert(ret > 0); return ret; } diff --git a/server.h b/server.h index 3727997..d6e6e61 100644 --- a/server.h +++ b/server.h @@ -190,7 +190,7 @@ private: // Reads regular data fro ma socket. Returns -1 if the processing // should go to sleep (an error, or no data available yet), otherwise // the number of bytes read. - int read_nontls_data(Client *client, char *buf, size_t max_size); + int read_plain_data(Client *client, char *buf, size_t max_size); // Reads (decrypted) data from a TLS socket. Returns -1 if the processing // should go to sleep (an error, or no data available yet), otherwise diff --git a/tlse/ktls.h b/tlse/ktls.h index bbcc4f3..7ed59c4 100644 --- a/tlse/ktls.h +++ b/tlse/ktls.h @@ -38,6 +38,7 @@ /* TLS socket options */ #define TLS_TX 1 /* Set transmit parameters */ +#define TLS_RX 2 /* Set receive parameters */ /* Supported versions */ #define TLS_VERSION_MINOR(ver) ((ver) & 0xFF) diff --git a/tlse/tlse.c b/tlse/tlse.c index dac0263..9b70bc1 100644 --- a/tlse/tlse.c +++ b/tlse/tlse.c @@ -8187,6 +8187,15 @@ int tls_unmake_ktls(struct TLSContext *context, int socket) { } memcpy(crypto_info.rec_seq, &context->local_sequence_number, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE); context->local_sequence_number = ntohll(context->local_sequence_number); +#ifdef TLS_RX + crypt_info_size = sizeof(crypto_info); + if (getsockopt(socket, SOL_TLS, TLS_RX, &crypto_info, &crypt_info_size)) { + DEBUG_PRINT("ERROR IN getsockopt\n"); + return TLS_GENERIC_ERROR; + } + memcpy(crypto_info.rec_seq, &context->remote_sequence_number, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE); + context->remote_sequence_number = ntohll(context->remote_sequence_number); +#endif return 0; #endif DEBUG_PRINT("TLSe COMPILED WITHOUT kTLS SUPPORT\n"); @@ -8217,7 +8226,7 @@ int tls_make_ktls(struct TLSContext *context, int socket) { return TLS_FEATURE_NOT_SUPPORTED; } #ifdef WITH_KTLS - if (context->exportable_size < TLS_CIPHER_AES_GCM_128_KEY_SIZE) { + if (context->exportable_size < TLS_CIPHER_AES_GCM_128_KEY_SIZE * 2) { DEBUG_PRINT("INVALID KEY SIZE\n"); return TLS_GENERIC_ERROR; } @@ -8231,7 +8240,26 @@ int tls_make_ktls(struct TLSContext *context, int socket) { memcpy(crypto_info.rec_seq, &local_sequence_number, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE); memcpy(crypto_info.key, context->exportable_keys, TLS_CIPHER_AES_GCM_128_KEY_SIZE); memcpy(crypto_info.salt, context->crypto.ctx_local_mac.local_aead_iv, TLS_CIPHER_AES_GCM_128_SALT_SIZE); + setsockopt(socket, SOL_TCP, TCP_ULP, "tls", sizeof("tls")); + +#ifdef TLS_RX + // kernel 4.17 adds TLS_RX support + struct tls12_crypto_info_aes_gcm_128 crypto_info_read; + + crypto_info_read.info.version = TLS_1_2_VERSION; + crypto_info_read.info.cipher_type = TLS_CIPHER_AES_GCM_128; + + uint64_t remote_sequence_number = htonll(context->remote_sequence_number); + memcpy(crypto_info_read.iv, &remote_sequence_number, TLS_CIPHER_AES_GCM_128_IV_SIZE); + memcpy(crypto_info_read.rec_seq, &remote_sequence_number, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE); + memcpy(crypto_info_read.key, context->exportable_keys + TLS_CIPHER_AES_GCM_128_KEY_SIZE, TLS_CIPHER_AES_GCM_128_KEY_SIZE); + memcpy(crypto_info_read.salt, context->crypto.ctx_remote_mac.remote_aead_iv, TLS_CIPHER_AES_GCM_128_SALT_SIZE); + + int err = setsockopt(socket, SOL_TLS, TLS_RX, &crypto_info_read, sizeof(crypto_info_read)); + if (err) + return err; +#endif return setsockopt(socket, SOL_TLS, TLS_TX, &crypto_info, sizeof(crypto_info)); #else DEBUG_PRINT("TLSe COMPILED WITHOUT kTLS SUPPORT\n"); -- 2.39.2