diff --git a/docs/config/security.en.md b/docs/config/security.en.md index 81dac7d6..6e8a2932 100644 --- a/docs/config/security.en.md +++ b/docs/config/security.en.md @@ -25,7 +25,7 @@ Most of them can be set in /etc/vitastor/vitastor.conf and in etcd, but don't su - [vault_timeout_ms](#vault_timeout_ms) - [vault_error_timeout_sec](#vault_error_timeout_sec) - [vault_refresh_leeway_sec](#vault_refresh_leeway_sec) -- [max_aes_xts_pool_size](#max_aes_xts_pool_size) +- [max_cipher_pool_size](#max_cipher_pool_size) ## etcd_client_cert @@ -141,10 +141,10 @@ Time (in seconds) to wait before retrying after receiving an error from Vault. Extra time (in seconds) before real Vault token lease_timeout to refresh it, just in case of system clock drift. -## max_aes_xts_pool_size +## max_cipher_pool_size - Type: integer - Default: 256 -Maximum number of OpenSSL encryption contexts cached in OSD memory. Probably -doesn't require modification. +Maximum number of OpenSSL cipher contexts cached in OSD memory, counted separately +for each cipher and for encryption/decryption. Probably doesn't require modification. diff --git a/docs/config/security.ru.md b/docs/config/security.ru.md index ac0455f0..7f6fb13f 100644 --- a/docs/config/security.ru.md +++ b/docs/config/security.ru.md @@ -27,7 +27,7 @@ OSD, мониторами и клиентами. - [vault_timeout_ms](#vault_timeout_ms) - [vault_error_timeout_sec](#vault_error_timeout_sec) - [vault_refresh_leeway_sec](#vault_refresh_leeway_sec) -- [max_aes_xts_pool_size](#max_aes_xts_pool_size) +- [max_cipher_pool_size](#max_cipher_pool_size) ## etcd_client_cert @@ -145,10 +145,10 @@ OSD, клиенты и мониторы должны иметь разные п Зазор времени (в секундах), чтобы обновлять токены Vault чуть раньше их реального lease_timeout, на случай "ухода" системных часов. -## max_aes_xts_pool_size +## max_cipher_pool_size - Тип: целое число - Значение по умолчанию: 256 -Максимальное количество кэшируемых в памяти OSD контекстов шифрования OpenSSL. -Вряд ли требует изменения. +Максимальное количество кэшируемых в памяти OSD контекстов шифра OpenSSL, учитываемое +отдельно для каждого шифра и для шифрования и расшифровки. Вряд ли требует изменения. diff --git a/docs/config/src/security.yml b/docs/config/src/security.yml index 8fd88fbb..d667312d 100644 --- a/docs/config/src/security.yml +++ b/docs/config/src/security.yml @@ -120,12 +120,12 @@ info_ru: | Зазор времени (в секундах), чтобы обновлять токены Vault чуть раньше их реального lease_timeout, на случай "ухода" системных часов. -- name: max_aes_xts_pool_size +- name: max_cipher_pool_size type: int default: 256 info: | - Maximum number of OpenSSL encryption contexts cached in OSD memory. Probably - doesn't require modification. + Maximum number of OpenSSL cipher contexts cached in OSD memory, counted separately + for each cipher and for encryption/decryption. Probably doesn't require modification. info_ru: | - Максимальное количество кэшируемых в памяти OSD контекстов шифрования OpenSSL. - Вряд ли требует изменения. + Максимальное количество кэшируемых в памяти OSD контекстов шифра OpenSSL, учитываемое + отдельно для каждого шифра и для шифрования и расшифровки. Вряд ли требует изменения. diff --git a/src/client/messenger.cpp b/src/client/messenger.cpp index 76de6008..d1a26aaf 100644 --- a/src/client/messenger.cpp +++ b/src/client/messenger.cpp @@ -236,15 +236,23 @@ osd_messenger_t::~osd_messenger_t() rdmacm_evch = NULL; } #endif - for (auto encrypt_ctx: encrypt_ctx_pool) + for (auto encrypt_ctx: encrypt_xts_pool) { destroy_aes_xts_encrypt(encrypt_ctx); } - for (auto decrypt_ctx: decrypt_ctx_pool) + for (auto decrypt_ctx: decrypt_xts_pool) { destroy_aes_xts_decrypt(decrypt_ctx); } #ifdef WITH_OPENSSL + for (EVP_CIPHER_CTX *ctx: encrypt_gcm_pool) + { + EVP_CIPHER_CTX_free(ctx); + } + for (EVP_CIPHER_CTX *ctx: decrypt_gcm_pool) + { + EVP_CIPHER_CTX_free(ctx); + } if (ssl_ctx) { SSL_CTX_free(ssl_ctx); @@ -285,9 +293,9 @@ void osd_messenger_t::parse_config(const json11::Json & config) if (!this->rdma_max_msg || this->rdma_max_msg > 128*1024*1024) this->rdma_max_msg = 129*1024; #endif - this->max_aes_xts_pool_size = config["max_aes_xts_pool_size"].uint64_value(); - if (!this->max_aes_xts_pool_size) - this->max_aes_xts_pool_size = 256; + this->max_cipher_pool_size = config["max_cipher_pool_size"].uint64_value(); + if (!this->max_cipher_pool_size) + this->max_cipher_pool_size = 256; if (config["proto_checksums"].is_null()) this->use_proto_checksums = MSGR_CSUM_PAYLOAD; else if (config["proto_checksums"].is_bool()) @@ -825,23 +833,7 @@ void osd_messenger_t::ssl_init(osd_client_t *cl, bool server_mode) } else if (!test_osd_aes_key.empty()) { - int r; - cl->enc_ctx = EVP_CIPHER_CTX_new(); - assert(cl->enc_ctx); - r = EVP_EncryptInit_ex(cl->enc_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); - assert(r == 1); - r = EVP_CIPHER_CTX_set_padding(cl->enc_ctx, 0); - assert(r == 1); - r = EVP_CIPHER_CTX_ctrl(cl->enc_ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL); - assert(r == 1); - cl->dec_ctx = EVP_CIPHER_CTX_new(); - assert(cl->dec_ctx); - r = EVP_DecryptInit_ex(cl->dec_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); - assert(r == 1); - r = EVP_CIPHER_CTX_set_padding(cl->dec_ctx, 0); - assert(r == 1); - r = EVP_CIPHER_CTX_ctrl(cl->dec_ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL); - assert(r == 1); + cl->gcm_enabled = true; } } diff --git a/src/client/messenger.h b/src/client/messenger.h index def1885b..7aa3c659 100644 --- a/src/client/messenger.h +++ b/src/client/messenger.h @@ -102,6 +102,7 @@ struct osd_client_t size_t ssl_read_header_size = 0; bool ssl_more_to_buffer = false; + bool gcm_enabled = false; EVP_CIPHER_CTX *enc_ctx = NULL; uint8_t enc_tag[16]; size_t enc_tag_size = 0; @@ -123,7 +124,7 @@ struct osd_client_t uint64_t read_op_id = 1; bool check_sequencing = false; bool enable_pg_locks = false; - op_aes_xts_decrypt_t *decrypt_ctx = NULL; + op_aes_xts_decrypt_t *xts_dec_ctx = NULL; size_t read_op_inline_decrypt_pos = 0; size_t read_op_inline_decrypt_in = 0; int proto_csum_status = 0; @@ -149,7 +150,7 @@ struct osd_client_t size_t send_list_size = 0; std::deque send_free_ops; std::vector zc_free_list; - op_aes_xts_encrypt_t *encrypt_ctx = NULL; + op_aes_xts_encrypt_t *xts_enc_ctx = NULL; XXH3_state_t* write_csum_state = NULL; ~osd_client_t(); @@ -218,7 +219,7 @@ protected: bool use_sync_send_recv = false; int min_zerocopy_send_size = DEFAULT_MIN_ZEROCOPY_SEND_SIZE; int iothread_count = 0; - int max_aes_xts_pool_size = 256; + int max_cipher_pool_size = 256; std::string tls_cert; std::string tls_key; @@ -256,8 +257,11 @@ protected: // We don't use ringloop->set_immediate here because we may have no ringloop in client :) std::deque set_immediate_ops; - std::vector encrypt_ctx_pool; - std::vector decrypt_ctx_pool; + std::vector encrypt_xts_pool; + std::vector decrypt_xts_pool; + + std::vector encrypt_gcm_pool; + std::vector decrypt_gcm_pool; public: timerfd_manager_t *tfd = NULL; diff --git a/src/client/msgr_encrypt.cpp b/src/client/msgr_encrypt.cpp index b29d9858..3a7b0297 100644 --- a/src/client/msgr_encrypt.cpp +++ b/src/client/msgr_encrypt.cpp @@ -335,23 +335,23 @@ void destroy_aes_xts_decrypt(op_aes_xts_decrypt_t *decrypt_ctx) void osd_messenger_t::op_encrypted_copy_buf(osd_client_t *cl, uint8_t *enc_buf, size_t enc_len, uint8_t *plain, size_t plain_len, size_t & done_plain, size_t & done_enc) { - if (!cl->encrypt_ctx) + if (!cl->xts_enc_ctx) { - if (encrypt_ctx_pool.size()) + if (encrypt_xts_pool.size()) { - cl->encrypt_ctx = encrypt_ctx_pool.back(); - encrypt_ctx_pool.pop_back(); + cl->xts_enc_ctx = encrypt_xts_pool.back(); + encrypt_xts_pool.pop_back(); } else - cl->encrypt_ctx = new op_aes_xts_encrypt_t(); + cl->xts_enc_ctx = new op_aes_xts_encrypt_t(); assert(cl->write_op->enc->key_chain[0]); - cl->encrypt_ctx->start(cl->write_op->enc->key_chain[0], cl->write_op->req.rw.offset, cl->write_op->enc->bitmap_granularity); + cl->xts_enc_ctx->start(cl->write_op->enc->key_chain[0], cl->write_op->req.rw.offset, cl->write_op->enc->bitmap_granularity); } - while (done_enc < enc_len && (done_plain < plain_len || cl->encrypt_ctx->has_buffered())) + while (done_enc < enc_len && (done_plain < plain_len || cl->xts_enc_ctx->has_buffered())) { size_t done_in = 0; size_t done_out = 0; - cl->encrypt_ctx->update(plain+done_plain, plain_len-done_plain, enc_buf+done_enc, enc_len-done_enc, done_in, done_out); + cl->xts_enc_ctx->update(plain+done_plain, plain_len-done_plain, enc_buf+done_enc, enc_len-done_enc, done_in, done_out); if (cl->write_csum_state && done_out > 0) XXH3_64bits_update(cl->write_csum_state, enc_buf+done_enc, done_out); done_enc += done_out; @@ -368,7 +368,7 @@ void osd_messenger_t::op_decrypted_copy_buf(osd_client_t *cl, uint8_t *enc_buf, size_t done_in = 0; size_t done_out = 0; // plain == NULL means skip output - cl->decrypt_ctx->update(enc_buf+done_enc, enc_len-done_enc, plain ? plain+done_plain : NULL, plain_len-done_plain, done_in, done_out); + cl->xts_dec_ctx->update(enc_buf+done_enc, enc_len-done_enc, plain ? plain+done_plain : NULL, plain_len-done_plain, done_in, done_out); if (cl->read_csum_state && done_in > 0) XXH3_64bits_update(cl->read_csum_state, enc_buf+done_enc, done_in); done_enc += done_in; @@ -380,18 +380,18 @@ void osd_messenger_t::op_decrypted_copy_buf(osd_client_t *cl, uint8_t *enc_buf, void osd_messenger_t::op_decrypt_start(osd_client_t* cl) { - if (!cl->decrypt_ctx) + if (!cl->xts_dec_ctx) { - if (decrypt_ctx_pool.size()) + if (decrypt_xts_pool.size()) { - cl->decrypt_ctx = decrypt_ctx_pool.back(); - decrypt_ctx_pool.pop_back(); + cl->xts_dec_ctx = decrypt_xts_pool.back(); + decrypt_xts_pool.pop_back(); } else - cl->decrypt_ctx = new op_aes_xts_decrypt_t(); + cl->xts_dec_ctx = new op_aes_xts_decrypt_t(); auto & enc = cl->read_op->enc; assert(cl->read_op->req.hdr.opcode == OSD_OP_READ); - cl->decrypt_ctx->start(enc->key_chain, enc->chain_size, + cl->xts_dec_ctx->start(enc->key_chain, enc->chain_size, (cl->read_op->req.rw.flags & OSD_OP_RETURN_CHAIN) ? (uint8_t*)cl->read_op->bitmap + enc->read_chain_bitmap_pos : 0, cl->read_op->req.rw.offset, enc->bitmap_granularity); } @@ -423,7 +423,7 @@ void osd_messenger_t::op_decrypt_inline(osd_client_t* cl) size_t out_len = op->iov.buf[j].iov_len - from_out; size_t done_in = 0; size_t done_out = 0; - cl->decrypt_ctx->update(in, in_len, out, out_len, done_in, done_out); + cl->xts_dec_ctx->update(in, in_len, out, out_len, done_in, done_out); if (done_in >= in_len) { i++; @@ -444,24 +444,24 @@ void osd_messenger_t::op_decrypt_inline(osd_client_t* cl) void osd_messenger_t::op_decrypt_free(osd_client_t* cl) { - if (cl->decrypt_ctx) + if (cl->xts_dec_ctx) { - if (decrypt_ctx_pool.size() > max_aes_xts_pool_size) - delete cl->decrypt_ctx; + if (decrypt_xts_pool.size() > max_cipher_pool_size) + delete cl->xts_dec_ctx; else - decrypt_ctx_pool.push_back(cl->decrypt_ctx); - cl->decrypt_ctx = NULL; + decrypt_xts_pool.push_back(cl->xts_dec_ctx); + cl->xts_dec_ctx = NULL; } } void osd_messenger_t::op_encrypt_free(osd_client_t* cl) { - if (cl->encrypt_ctx) + if (cl->xts_enc_ctx) { - if (encrypt_ctx_pool.size() > max_aes_xts_pool_size) - delete cl->encrypt_ctx; + if (encrypt_xts_pool.size() > max_cipher_pool_size) + delete cl->xts_enc_ctx; else - encrypt_ctx_pool.push_back(cl->encrypt_ctx); - cl->encrypt_ctx = NULL; + encrypt_xts_pool.push_back(cl->xts_enc_ctx); + cl->xts_enc_ctx = NULL; } } diff --git a/src/client/msgr_receive.cpp b/src/client/msgr_receive.cpp index 854baadb..d577fc86 100644 --- a/src/client/msgr_receive.cpp +++ b/src/client/msgr_receive.cpp @@ -288,6 +288,26 @@ public: void reset() { from = cl->read_op_pos; + if (!cl->dec_ctx) + { + if (msgr->decrypt_gcm_pool.size()) + { + cl->dec_ctx = msgr->decrypt_gcm_pool.back(); + msgr->decrypt_gcm_pool.pop_back(); + } + else + { + cl->dec_ctx = EVP_CIPHER_CTX_new(); + assert(cl->dec_ctx); + int r = EVP_DecryptInit_ex(cl->dec_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); + if (r != 1) + { + fprintf(stderr, "DecryptInit error: "); + ERR_print_errors_fp(stderr); + abort(); + } + } + } uint8_t iv[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; int r = EVP_DecryptInit_ex(cl->dec_ctx, NULL, NULL, (uint8_t*)msgr->test_osd_aes_key.data(), iv); if (r != 1) @@ -401,6 +421,11 @@ public: cl->io_error = true; return false; } + if (msgr->decrypt_gcm_pool.size() < msgr->max_cipher_pool_size) + msgr->decrypt_gcm_pool.push_back(cl->dec_ctx); + else + EVP_CIPHER_CTX_free(cl->dec_ctx); + cl->dec_ctx = NULL; cl->dec_tag_size = 0; assert(len == 0); return true; @@ -462,7 +487,7 @@ public: bool read(uint8_t *dst, size_t dst_len, int flags) override { - if (cl->dec_ctx) + if (cl->gcm_enabled) return false; // FIXME Only for tests, use copy-only with AES if (from >= dst_len) { @@ -496,7 +521,7 @@ public: bool finish() override { - if (cl->dec_ctx) + if (cl->gcm_enabled) return false; return true; } @@ -692,7 +717,7 @@ void osd_messenger_t::handle_immediate_ops() bool osd_messenger_t::handle_read_buffer(osd_client_t *cl, uint8_t *curbuf, size_t bufsize) { - if (cl->dec_ctx) + if (cl->gcm_enabled) { return handle_buffer_with(cl, curbuf, bufsize); } diff --git a/src/client/msgr_send.cpp b/src/client/msgr_send.cpp index 78a5e454..d87e486f 100644 --- a/src/client/msgr_send.cpp +++ b/src/client/msgr_send.cpp @@ -247,6 +247,31 @@ public: void reset() { from = cl->write_op_pos; + init_ctx(msgr, cl); + } + + static void init_ctx(osd_messenger_t* msgr, osd_client_t *cl) + { + if (!cl->enc_ctx) + { + if (msgr->encrypt_gcm_pool.size()) + { + cl->enc_ctx = msgr->encrypt_gcm_pool.back(); + msgr->encrypt_gcm_pool.pop_back(); + } + else + { + cl->enc_ctx = EVP_CIPHER_CTX_new(); + assert(cl->enc_ctx); + int r = EVP_EncryptInit_ex(cl->enc_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); + if (r != 1) + { + fprintf(stderr, "EncryptInit error: "); + ERR_print_errors_fp(stderr); + abort(); + } + } + } uint8_t iv[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; int r = EVP_EncryptInit_ex(cl->enc_ctx, NULL, NULL, (uint8_t*)msgr->test_osd_aes_key.data(), iv); if (r != 1) @@ -257,6 +282,15 @@ public: } } + static void free_ctx(osd_messenger_t* msgr, osd_client_t *cl) + { + if (msgr->encrypt_gcm_pool.size() < msgr->max_cipher_pool_size) + msgr->encrypt_gcm_pool.push_back(cl->enc_ctx); + else + EVP_CIPHER_CTX_free(cl->enc_ctx); + cl->enc_ctx = NULL; + } + bool write(uint8_t *src, size_t src_len, int flags) override { if (from >= src_len) @@ -346,11 +380,16 @@ public: memcpy(curbuf+done, cl->enc_tag+16-cl->enc_tag_size, n); done += n; cl->enc_tag_size -= n; - return !cl->enc_tag_size; + if (cl->enc_tag_size > 0) + return false; } - // The whole tag fits at once - write_tag_to(cl, curbuf+done); - done += 16; + else + { + // The whole tag fits at once + write_tag_to(cl, curbuf+done); + done += 16; + } + free_ctx(msgr, cl); return true; } @@ -417,16 +456,9 @@ public: from = cl->write_op_pos; enc_size = 0; done_enc = 0; - if (cl->enc_ctx) + if (cl->gcm_enabled) { - uint8_t iv[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - int r = EVP_EncryptInit_ex(cl->enc_ctx, NULL, NULL, (uint8_t*)msgr->test_osd_aes_key.data(), iv); - if (r != 1) - { - fprintf(stderr, "EncryptInit error: "); - ERR_print_errors_fp(stderr); - abort(); - } + gcm_op_writer_t::init_ctx(msgr, cl); } } @@ -551,6 +583,7 @@ public: // FIXME coalesce entries in ssl_out_buf cl->send_list.push_back((iovec){ .iov_base = cl->ssl_out_buf+cl->ssl_out_buf_size, .iov_len = 16 }); cl->ssl_out_buf_size += 16; + gcm_op_writer_t::free_ctx(msgr, cl); } return true; } @@ -791,7 +824,7 @@ bool osd_messenger_t::try_send(osd_client_t *cl) size_t osd_messenger_t::copy_ops_to(osd_client_t *cl, uint8_t *dst, size_t dst_len) { - if (cl->enc_ctx) + if (cl->gcm_enabled) { return copy_ops_to_with(cl, dst, dst_len); } diff --git a/src/client/msgr_stop.cpp b/src/client/msgr_stop.cpp index 804f2328..bf997350 100644 --- a/src/client/msgr_stop.cpp +++ b/src/client/msgr_stop.cpp @@ -83,21 +83,21 @@ void osd_messenger_t::stop_client(uint64_t client_id, bool force_delete) fprintf(stderr, "[OSD %ju] Stopping client %ju (regular client)\n", osd_num, client_id); } } - if (cl->encrypt_ctx) + if (cl->xts_enc_ctx) { - if (encrypt_ctx_pool.size() > max_aes_xts_pool_size) - destroy_aes_xts_encrypt(cl->encrypt_ctx); + if (encrypt_xts_pool.size() > max_cipher_pool_size) + destroy_aes_xts_encrypt(cl->xts_enc_ctx); else - encrypt_ctx_pool.push_back(cl->encrypt_ctx); - cl->encrypt_ctx = NULL; + encrypt_xts_pool.push_back(cl->xts_enc_ctx); + cl->xts_enc_ctx = NULL; } - if (cl->decrypt_ctx) + if (cl->xts_dec_ctx) { - if (decrypt_ctx_pool.size() > max_aes_xts_pool_size) - destroy_aes_xts_decrypt(cl->decrypt_ctx); + if (decrypt_xts_pool.size() > max_cipher_pool_size) + destroy_aes_xts_decrypt(cl->xts_dec_ctx); else - decrypt_ctx_pool.push_back(cl->decrypt_ctx); - cl->decrypt_ctx = NULL; + decrypt_xts_pool.push_back(cl->xts_dec_ctx); + cl->xts_dec_ctx = NULL; } // First set state to STOPPED so another stop_client() call doesn't try to free it again cl->refs++;