From a5dbf741230946b705cdf7cbcacdcbbf6852f23e Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Tue, 5 May 2026 02:54:27 +0300 Subject: [PATCH] Add support for full AES-GCM including double encryption of AES-XTS :D --- .gitea/workflows/test.yml | 18 +++ src/client/messenger.cpp | 56 +++++--- src/client/messenger.h | 7 +- src/client/msgr_encrypt.cpp | 76 ++++++++-- src/client/msgr_encrypt.h | 8 +- src/client/msgr_handshake.cpp | 67 +++++++-- src/client/msgr_handshake.h | 5 +- src/client/msgr_op.cpp | 4 - src/client/msgr_op.h | 1 - src/client/msgr_rdma.cpp | 7 +- src/client/msgr_receive.cpp | 68 ++++----- src/client/msgr_send.cpp | 240 +++++++++++++------------------ src/client/msgr_stop.cpp | 10 +- src/osd/osd_secondary.cpp | 13 +- src/test/test_cluster_client.cpp | 22 +-- tests/run_tests.sh | 1 + 16 files changed, 358 insertions(+), 245 deletions(-) diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index a349f21e..73575de4 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -792,6 +792,24 @@ jobs: echo "" done + test_snapshot_chain_enc_gcm: + runs-on: ubuntu-latest + needs: build + container: ${{env.TEST_IMAGE}}:${{github.sha}} + steps: + - name: Run test + id: test + timeout-minutes: 3 + run: TEST_NAME=enc_gcm ENCRYPTED=1 VITASTOR_CFG=',"proto_checksums":"gcm"' /root/vitastor/tests/test_snapshot_chain.sh + - name: Print logs + if: always() && steps.test.outcome == 'failure' + run: | + for i in /root/vitastor/testdata/*.log /root/vitastor/testdata/*.txt; do + echo "-------- $i --------" + cat $i + echo "" + done + test_old_snapshot_chain: runs-on: ubuntu-latest needs: build diff --git a/src/client/messenger.cpp b/src/client/messenger.cpp index dcaa7bd9..9d0ea2d4 100644 --- a/src/client/messenger.cpp +++ b/src/client/messenger.cpp @@ -197,19 +197,34 @@ osd_messenger_t::~osd_messenger_t() destroy_tls(); } +static int parse_proto_checksums(const json11::Json & val, int default_value) +{ + if (val.is_string()) + { + const auto & str = val.string_value(); + if (str == "full") + return MSGR_CSUM_FULL; + else if (str == "payload") + return MSGR_CSUM_PAYLOAD; + else if (str == "gcm") + return MSGR_CSUM_GCM; + else if (str == "none") + return 0; + else if (str == "") + return default_value; + } + else if (val.is_null()) + return default_value; + fprintf(stderr, "proto_checksums should be \"full\", \"payload\", \"gcm\", \"none\"" + ", \"\" or null (default), but it is: %s\n", val.dump().c_str()); + exit(1); +} + void osd_messenger_t::parse_config(const json11::Json & config, bool init) { 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()) - this->use_proto_checksums = config["proto_checksums"].bool_value() ? MSGR_CSUM_FULL : 0; - else if (config["proto_checksums"].string_value() != "") - this->use_proto_checksums = config["proto_checksums"].string_value() == "full" ? MSGR_CSUM_FULL : MSGR_CSUM_PAYLOAD; - else - this->use_proto_checksums = 0; this->receive_buffer_size = (uint32_t)config["tcp_header_buffer_size"].uint64_value(); if (!this->receive_buffer_size || this->receive_buffer_size > 1024*1024*1024) this->receive_buffer_size = 65536; @@ -275,6 +290,8 @@ void osd_messenger_t::parse_config(const json11::Json & config, bool init) osd_tls_ca = config["osd_ca"].string_value(); client_tls_ca = config["client_ca"].string_value(); } + this->use_proto_checksums = parse_proto_checksums(config["proto_checksums"], MSGR_CSUM_PAYLOAD); + this->force_proto_checksums = parse_proto_checksums(config["force_proto_checksums"], tls_cert != "" ? MSGR_CSUM_PAYLOAD : 0); if (!osd_num) this->iothread_count = (uint32_t)config["client_iothread_count"].uint64_value(); else @@ -653,6 +670,21 @@ void osd_messenger_t::check_peer_config(osd_client_t *cl) err = !check_config_hook(cl, config); } } + if (!err && use_proto_checksums) + { + auto peer_csums = config["features"]["proto_checksums"].uint64_value(); + if (peer_csums == MSGR_CSUM_GCM && use_proto_checksums == MSGR_CSUM_GCM && cl->gcm_enabled) + cl->proto_csum_status = MSGR_CSUM_GCM; + else if (peer_csums == MSGR_CSUM_FULL && use_proto_checksums == MSGR_CSUM_FULL) + cl->proto_csum_status = MSGR_CSUM_FULL; + else if (peer_csums && use_proto_checksums) + cl->proto_csum_status = MSGR_CSUM_PAYLOAD; + if (cl->proto_csum_status < force_proto_checksums) + { + fprintf(stderr, "Error: OSD %ju use_proto_checksums security level is lower than force_proto_checksums\n", cl->osd_num); + err = true; + } + } if (err) { osd_num_t peer_osd = cl->osd_num; @@ -661,14 +693,6 @@ void osd_messenger_t::check_peer_config(osd_client_t *cl) delete op; return; } - if (use_proto_checksums) - { - auto peer_csums = config["features"]["proto_checksums"].uint64_value(); - if (peer_csums == MSGR_CSUM_FULL && use_proto_checksums == MSGR_CSUM_FULL) - cl->proto_csum_status = MSGR_CSUM_FULL; - else if (peer_csums && use_proto_checksums) - cl->proto_csum_status = MSGR_CSUM_PAYLOAD; - } #ifdef WITH_RDMA if (!use_rdmacm && cl->rdma_conn && config["rdma_address"].is_string()) { diff --git a/src/client/messenger.h b/src/client/messenger.h index de513ba7..32003393 100644 --- a/src/client/messenger.h +++ b/src/client/messenger.h @@ -41,7 +41,8 @@ #define MSGR_CSUM_PAYLOAD 1 #define MSGR_CSUM_FULL 2 -#define MSGR_CSUM_NEG 4 +#define MSGR_CSUM_GCM 4 +#define MSGR_CSUM_NEG 8 #define VITASTOR_CONFIG_PATH "/etc/vitastor/vitastor.conf" @@ -92,9 +93,6 @@ struct osd_client_t msgr_rdma_connection_t *rdma_conn = NULL; #endif - uint8_t *ssl_out_buf = NULL; - size_t ssl_out_buf_size = 0, ssl_out_buf_cap = 0; - bool gcm_enabled = false; msgr_handshake_i *hs = NULL; msgr_handshake_result_t hs_result; @@ -290,6 +288,7 @@ public: std::vector all_osd_networks; std::vector all_osd_network_masks; int use_proto_checksums = 0; + int force_proto_checksums = 0; // op statistics osd_op_stats_t stats, recovery_stats; diff --git a/src/client/msgr_encrypt.cpp b/src/client/msgr_encrypt.cpp index 20d66dbd..720355ce 100644 --- a/src/client/msgr_encrypt.cpp +++ b/src/client/msgr_encrypt.cpp @@ -44,9 +44,10 @@ op_aes_xts_encrypt_t::~op_aes_xts_encrypt_t() free(tmp); } -void op_aes_xts_encrypt_t::start(uint8_t *key, uint64_t start_offset, size_t block_size) +void op_aes_xts_encrypt_t::start(osd_client_t *cl, uint8_t *key, uint64_t start_offset, size_t block_size) { assert(!encrypted); + this->cl = cl; this->start_offset = start_offset; this->key = key; this->block_size = block_size; @@ -91,6 +92,28 @@ void op_aes_xts_encrypt_t::encrypt_block(uint8_t *in, uint8_t *out) #endif } +static inline void copy_or_gcm(osd_client_t *cl, uint8_t *out, uint8_t *in, size_t n) +{ + if (cl->proto_csum_status != MSGR_CSUM_GCM) + memcpy(out, in, n); + else + { +#ifdef WITH_ISAL_CRYPTO + int r = isal_aes_gcm_enc_256_update(&cl->my_key_isal, cl->enc_ctx, out, in, n); + assert(!r); +#else + int actual_out; + if (EVP_EncryptUpdate(cl->enc_ctx, out, &actual_out, in, n) != 1) + { + fprintf(stderr, "EncryptUpdate error: "); + ERR_print_errors_fp(stderr); + abort(); + } + assert(actual_out == n); +#endif + } +} + void op_aes_xts_encrypt_t::update(uint8_t *in, size_t max_in, uint8_t *out, size_t max_out, size_t & done_in, size_t & done_out) { // Fucking AES-XTS implementations (all of them) don't have streaming support, @@ -104,7 +127,7 @@ void op_aes_xts_encrypt_t::update(uint8_t *in, size_t max_in, uint8_t *out, size assert(tmp); if (max_out > block_size - tmp_pos) max_out = block_size - tmp_pos; - memcpy(out, tmp + tmp_pos, max_out); + copy_or_gcm(cl, out, tmp + tmp_pos, max_out); done_out += max_out; tmp_pos += max_out; if (tmp_pos >= block_size) @@ -137,7 +160,7 @@ void op_aes_xts_encrypt_t::update(uint8_t *in, size_t max_in, uint8_t *out, size memcpy(tmp + offset%block_size, in, max_in); encrypt_block(tmp, tmp); encrypted = true; - memcpy(out, tmp, max_out); + copy_or_gcm(cl, out, tmp, max_out); tmp_pos = max_out; done_in += max_in-1; offset += max_in; @@ -147,6 +170,8 @@ void op_aes_xts_encrypt_t::update(uint8_t *in, size_t max_in, uint8_t *out, size { // Full block - simplest case encrypt_block(in, out); + if (cl->proto_csum_status == MSGR_CSUM_GCM) + copy_or_gcm(cl, out, out, block_size); done_in += block_size; offset += block_size; done_out += block_size; @@ -158,6 +183,8 @@ void op_aes_xts_encrypt_t::update(uint8_t *in, size_t max_in, uint8_t *out, size max_in = block_size - offset%block_size; memcpy(tmp + offset%block_size, in, max_in); encrypt_block(tmp, out); + if (cl->proto_csum_status == MSGR_CSUM_GCM) + copy_or_gcm(cl, out, out, block_size); done_in += max_in; offset += max_in; done_out += block_size; @@ -196,9 +223,10 @@ op_aes_xts_decrypt_t::~op_aes_xts_decrypt_t() free(tmp); } -void op_aes_xts_decrypt_t::start(uint8_t **key_chain, size_t chain_size, void *key_indexes, uint64_t start_offset, size_t block_size) +void op_aes_xts_decrypt_t::start(osd_client_t *cl, uint8_t **key_chain, size_t chain_size, void *key_indexes, uint64_t start_offset, size_t block_size) { assert(!decrypted); + this->cl = cl; this->start_offset = start_offset; this->key_chain = key_chain; this->chain_size = chain_size; @@ -269,6 +297,23 @@ void op_aes_xts_decrypt_t::decrypt_block(uint8_t *in, uint8_t *out) #endif } +static inline void gcm_dec(osd_client_t *cl, uint8_t *out, uint8_t *in, size_t n) +{ +#ifdef WITH_ISAL_CRYPTO + int r = isal_aes_gcm_dec_256_update(&cl->peer_key_isal, cl->dec_ctx, out, in, n); + assert(!r); +#else + int actual_out; + if (EVP_DecryptUpdate(cl->dec_ctx, out, &actual_out, in, n) != 1) + { + fprintf(stderr, "DecryptUpdate error: "); + ERR_print_errors_fp(stderr); + abort(); + } + assert(actual_out == n); +#endif +} + // out may be NULL, in this case all input is still decrypted to calculate checksums, // but part of it is skipped and not copied to out void op_aes_xts_decrypt_t::update(uint8_t *in, size_t max_in, uint8_t *out, size_t max_out, size_t & done_in, size_t & done_out) @@ -316,6 +361,8 @@ void op_aes_xts_decrypt_t::update(uint8_t *in, size_t max_in, uint8_t *out, size } max_in = block_size - offset%block_size; memcpy(tmp + offset%block_size, in, max_in); + if (cl->proto_csum_status == MSGR_CSUM_GCM) + gcm_dec(cl, tmp, tmp, block_size); decrypt_block(tmp, tmp); decrypted = true; if (out) @@ -328,7 +375,18 @@ void op_aes_xts_decrypt_t::update(uint8_t *in, size_t max_in, uint8_t *out, size else if (!(offset%block_size)) { // Full block - simplest case - if (out) + if (cl->proto_csum_status == MSGR_CSUM_GCM) + { + if (!tmp) + { + tmp = (uint8_t*)malloc_or_die(block_size); + tmp_size = block_size; + } + gcm_dec(cl, tmp, in, block_size); + if (out) + decrypt_block(tmp, out); + } + else decrypt_block(in, out); done_in += block_size; offset += block_size; @@ -341,6 +399,8 @@ void op_aes_xts_decrypt_t::update(uint8_t *in, size_t max_in, uint8_t *out, size max_in = block_size - offset%block_size; memcpy(tmp + offset%block_size, in, max_in); assert(out); + if (cl->proto_csum_status == MSGR_CSUM_GCM) + gcm_dec(cl, tmp, tmp, block_size); decrypt_block(tmp, out); done_in += max_in; offset += max_in; @@ -365,7 +425,7 @@ void osd_messenger_t::op_encrypted_copy_buf(osd_client_t *cl, uint8_t *enc_buf, else cl->xts_enc_ctx = new op_aes_xts_encrypt_t(); assert(cl->write_op->enc->key_chain[0]); - cl->xts_enc_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, cl->write_op->enc->key_chain[0], cl->write_op->req.rw.offset, cl->write_op->enc->bitmap_granularity); } while (done_plain < plain_len && done_enc < enc_len) { @@ -411,7 +471,7 @@ void osd_messenger_t::op_decrypt_start(osd_client_t* cl) 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->xts_dec_ctx->start(enc->key_chain, enc->chain_size, + cl->xts_dec_ctx->start(cl, 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); } @@ -561,7 +621,7 @@ void osd_messenger_t::init_tls_client(osd_client_t *cl) cl->gcm_enabled = true; cl->hs = hs_ctx->create(); cl->hs->init(cl->is_incoming); - if (cl->hs->get_out().size()) + if (cl->hs->out_size()) { if (cl->write_state == 0) { diff --git a/src/client/msgr_encrypt.h b/src/client/msgr_encrypt.h index 94c5f343..2d773934 100644 --- a/src/client/msgr_encrypt.h +++ b/src/client/msgr_encrypt.h @@ -12,11 +12,14 @@ #include #include +struct osd_client_t; + class op_aes_xts_encrypt_t { #ifndef WITH_ISAL_CRYPTO EVP_CIPHER_CTX *ctx = NULL; #endif + osd_client_t *cl = NULL; uint64_t start_offset = 0; uint8_t *key = NULL; size_t offset = 0; @@ -32,7 +35,7 @@ public: op_aes_xts_encrypt_t(); ~op_aes_xts_encrypt_t(); - void start(uint8_t *key, uint64_t start_offset, size_t block_size); + void start(osd_client_t *cl, uint8_t *key, uint64_t start_offset, size_t block_size); void update(uint8_t *in, size_t max_in, uint8_t *out, size_t max_out, size_t & done_in, size_t & done_out); }; @@ -43,6 +46,7 @@ class op_aes_xts_decrypt_t #ifndef WITH_ISAL_CRYPTO EVP_CIPHER_CTX *ctx = NULL; #endif + osd_client_t *cl = NULL; uint64_t start_offset = 0; uint8_t **key_chain = NULL; size_t chain_size = 0; @@ -61,7 +65,7 @@ public: op_aes_xts_decrypt_t(); ~op_aes_xts_decrypt_t(); - void start(uint8_t **key_chain, size_t chain_size, void *key_indexes, uint64_t start_offset, size_t block_size); + void start(osd_client_t *cl, uint8_t **key_chain, size_t chain_size, void *key_indexes, uint64_t start_offset, size_t block_size); void update(uint8_t *in, size_t max_in, uint8_t *out, size_t max_out, size_t & done_in, size_t & done_out); }; diff --git a/src/client/msgr_handshake.cpp b/src/client/msgr_handshake.cpp index 0c93c5de..2298989a 100644 --- a/src/client/msgr_handshake.cpp +++ b/src/client/msgr_handshake.cpp @@ -18,6 +18,7 @@ #include #include "msgr_handshake.h" +#include "malloc_or_die.h" #include "openssl_util.h" #include "str_util.h" @@ -84,7 +85,8 @@ class msgr_handshake_t: public msgr_handshake_i std::vector full_handshake; std::vector in_buf; - std::vector out_buf; + uint8_t *out_buf = NULL; + size_t out_buf_size = 0; std::string error; int state = 0; @@ -125,7 +127,10 @@ public: bool init(bool server_mode) override; ssize_t handle(uint8_t* in_buf, size_t in_size) override; bool done() override; - std::vector& get_out() override; + uint8_t *get_out() override; + size_t out_size() override; + void eat_out(size_t n) override; + void reset_out() override; msgr_handshake_result_t get_result() override; std::string get_error() override; }; @@ -247,6 +252,8 @@ bool msgr_handshake_ctx_t::derive_kdf(const uint8_t* insecret, size_t insecret_l msgr_handshake_t::~msgr_handshake_t() { + if (out_buf) + free(out_buf); if (peer_cert) X509_free(peer_cert); if (ec_key) @@ -288,6 +295,12 @@ static void copy_to(std::vector & buf, const void* src, uint32_t len) memcpy(buf.data() + old_size, src, len); } +static void copy_to_raw(uint8_t* & buf, const void* src, size_t len) +{ + memcpy(buf, src, len); + buf += len; +} + static void copy_to_with_len(std::vector & buf, const void* src, uint32_t len) { copy_to(buf, &len, sizeof(len)); @@ -442,9 +455,10 @@ bool msgr_handshake_t::make_client_init() size_t key_len = EVP_PKEY_get1_encoded_public_key(ec_key, &key); if (!key_len) return on_error("EVP_PKEY_get1_encoded_public_key: "); - const size_t old_len = out_buf.size(); - out_buf.resize(out_buf.size() + key_len + sizeof(msgr_handshake_hdr_t)); - uint8_t *buf = out_buf.data() + old_len; + const size_t old_out_size = out_buf_size; + out_buf_size += key_len + sizeof(msgr_handshake_hdr_t); + out_buf = (uint8_t*)realloc_or_die(out_buf, out_buf_size); + uint8_t *buf = out_buf + old_out_size; msgr_handshake_hdr_t *hdr = (msgr_handshake_hdr_t *)buf; hdr->msg_len = key_len + sizeof(msgr_handshake_hdr_t); hdr->magic = MSGR_HS_MAGIC; @@ -485,9 +499,12 @@ bool msgr_handshake_t::make_server_reply() } // Construct message hdr.msg_len = sizeof(msgr_handshake_hdr_t) + 4 + key_len + encrypt_data.size(); - copy_to(out_buf, &hdr, sizeof(hdr)); - copy_to_with_len(out_buf, key, key_len); - copy_to(out_buf, encrypt_data.data(), encrypt_data.size()); + out_buf = (uint8_t*)realloc_or_die(out_buf, (out_buf_size += hdr.msg_len)); + uint8_t *cur = out_buf + out_buf_size - hdr.msg_len; + copy_to_raw(cur, &hdr, sizeof(hdr)); + copy_to_raw(cur, &key_len, 4); + copy_to_raw(cur, key, key_len); + copy_to_raw(cur, encrypt_data.data(), encrypt_data.size()); OPENSSL_free(key); return true; } @@ -510,8 +527,10 @@ bool msgr_handshake_t::make_client_reply() return false; // Construct message hdr.msg_len = sizeof(msgr_handshake_hdr_t) + encrypt_data.size(); - copy_to(out_buf, &hdr, sizeof(hdr)); - copy_to(out_buf, encrypt_data.data(), encrypt_data.size()); + out_buf = (uint8_t*)realloc_or_die(out_buf, (out_buf_size += hdr.msg_len)); + uint8_t *cur = out_buf + out_buf_size - hdr.msg_len; + copy_to_raw(cur, &hdr, sizeof(hdr)); + copy_to_raw(cur, encrypt_data.data(), encrypt_data.size()); return true; } @@ -742,11 +761,37 @@ bool msgr_handshake_t::done() return (state == MSGR_HS_DONE); } -std::vector& msgr_handshake_t::get_out() +uint8_t *msgr_handshake_t::get_out() { return out_buf; } +size_t msgr_handshake_t::out_size() +{ + return out_buf_size; +} + +void msgr_handshake_t::eat_out(size_t n) +{ + if (n >= out_buf_size) + { + free(out_buf); + out_buf = NULL; + out_buf_size = 0; + } + else + { + memmove(out_buf, out_buf + n, out_buf_size - n); + out_buf_size -= n; + } +} + +void msgr_handshake_t::reset_out() +{ + out_buf = NULL; + out_buf_size = 0; +} + msgr_handshake_result_t msgr_handshake_t::get_result() { if (state != MSGR_HS_DONE) diff --git a/src/client/msgr_handshake.h b/src/client/msgr_handshake.h index b19469da..b68a178b 100644 --- a/src/client/msgr_handshake.h +++ b/src/client/msgr_handshake.h @@ -35,7 +35,10 @@ public: virtual bool init(bool server_mode) = 0; virtual ssize_t handle(uint8_t* in_buf, size_t in_size) = 0; virtual bool done() = 0; - virtual std::vector & get_out() = 0; + virtual uint8_t *get_out() = 0; + virtual size_t out_size() = 0; + virtual void eat_out(size_t n) = 0; + virtual void reset_out() = 0; virtual msgr_handshake_result_t get_result() = 0; virtual std::string get_error() = 0; }; diff --git a/src/client/msgr_op.cpp b/src/client/msgr_op.cpp index 05a9dad4..76c79e98 100644 --- a/src/client/msgr_op.cpp +++ b/src/client/msgr_op.cpp @@ -24,10 +24,6 @@ osd_op_t::~osd_op_t() // So we don't reuse it, but free it every time free(buf); } - if (enc_buf) - { - free(enc_buf); - } } bool osd_op_t::is_recovery_related() diff --git a/src/client/msgr_op.h b/src/client/msgr_op.h index 73d38a69..f67084d5 100644 --- a/src/client/msgr_op.h +++ b/src/client/msgr_op.h @@ -186,7 +186,6 @@ struct __attribute__((visibility("default"))) osd_op_t uint8_t *bitmap_buf = NULL; void *rmw_buf = NULL; std::shared_ptr enc; - uint8_t *enc_buf = NULL; uint64_t csum = 0; // network layer checksum osd_primary_op_data_t* op_data = NULL; std::function callback; diff --git a/src/client/msgr_rdma.cpp b/src/client/msgr_rdma.cpp index 494f9aa4..87d25f03 100644 --- a/src/client/msgr_rdma.cpp +++ b/src/client/msgr_rdma.cpp @@ -735,9 +735,12 @@ void osd_messenger_t::handle_rdma_events(msgr_rdma_context_t *rdma_context) if (rc->send_done_pos == rc->send_out_size) rc->send_done_pos = 0; assert(rc->send_done_pos < rc->send_out_size); - while (cl->send_free_ops.front()) + while (osd_op_t *op = cl->send_free_ops.front()) { - delete cl->send_free_ops.front(); + if (!((size_t)op & 7)) + delete op; + else + free((void*)((size_t)op & ~(size_t)7)); cl->send_free_ops.pop_front(); } cl->send_free_ops.pop_front(); diff --git a/src/client/msgr_receive.cpp b/src/client/msgr_receive.cpp index 780fe3d0..afdbc04b 100644 --- a/src/client/msgr_receive.cpp +++ b/src/client/msgr_receive.cpp @@ -170,41 +170,17 @@ public: if (done >= bufsize) return false; size_t n = dst_len-from; - if (!(flags & RDR_GCM)) + if (n > bufsize-done) + n = bufsize-done; + if (flags & RDR_XTS) { - if (n > bufsize-done) - n = bufsize-done; - if (flags & RDR_XTS) - { - msgr->op_decrypted_copy_buf(cl, curbuf, bufsize, dst, dst_len, from, done); - n = 0; - } - else - { - if (cl->read_csum_state && !(flags & RDR_NO_CSUM)) - { - // data may be skipped if dst == NULL but checksum is still calculated - XXH3_64bits_update(cl->read_csum_state, curbuf+done, n); - } - // Here, dst == NULL is allowed - if (dst != NULL) - memcpy(dst+from, curbuf+done, n); - done += n; - } - cl->read_op_pos += n; - from += n; - if (from < dst_len) - { - return false; - } + msgr->op_decrypted_copy_buf(cl, curbuf, bufsize, dst, dst_len, from, done); + n = 0; } - else + else if (flags & RDR_GCM) { // Here, dst == NULL is not allowed assert(dst != NULL); - size_t n = dst_len-from; - if (n > bufsize-done) - n = bufsize-done; #ifdef WITH_ISAL_CRYPTO int r = isal_aes_gcm_dec_256_update(&cl->peer_key_isal, cl->dec_ctx, dst+from, curbuf+done, n); assert(!r); @@ -223,12 +199,24 @@ public: XXH3_64bits_update(cl->read_csum_state, dst+from, n); } done += n; - from += n; - cl->read_op_pos += n; - if (from < dst_len) + } + else + { + if (cl->read_csum_state && !(flags & RDR_NO_CSUM)) { - return false; + // data may be skipped if dst == NULL but checksum is still calculated + XXH3_64bits_update(cl->read_csum_state, curbuf+done, n); } + // Here, dst == NULL is allowed + if (dst != NULL) + memcpy(dst+from, curbuf+done, n); + done += n; + } + cl->read_op_pos += n; + from += n; + if (from < dst_len) + { + return false; } from = 0; return true; @@ -605,7 +593,7 @@ bool osd_messenger_t::handle_read_buffer(osd_client_t *cl, uint8_t *curbuf, size } curbuf += done; bufsize -= done; - if (cl->hs->get_out().size()) + if (cl->hs->out_size()) { if (cl->write_state == 0) { @@ -613,7 +601,7 @@ bool osd_messenger_t::handle_read_buffer(osd_client_t *cl, uint8_t *curbuf, size write_ready_clients.push_back(cl->client_id); } } - if (cl->hs->done() && !cl->hs->get_out().size()) + if (cl->hs->done() && !cl->hs->out_size()) { // Delete hs when done and nothing to send delete cl->hs; @@ -933,7 +921,7 @@ bool osd_messenger_t::op_read_from(osd_client_t *cl, msgr_op_reader_t & rdr) { if (!rdr.read((uint8_t*)op->bitmap, op->req.sec_rw.attr_len, RDR_GCM)) return false; - if (!rdr.read((uint8_t*)op->buf, op->req.sec_rw.len, 0)) + if (!rdr.read((uint8_t*)op->buf, op->req.sec_rw.len, cl->proto_csum_status == MSGR_CSUM_GCM ? RDR_GCM : 0)) return false; } else if (op->req.hdr.opcode == OSD_OP_SEC_STABILIZE || @@ -949,7 +937,7 @@ bool osd_messenger_t::op_read_from(osd_client_t *cl, msgr_op_reader_t & rdr) } else if (op->req.hdr.opcode == OSD_OP_WRITE) { - if (!rdr.read((uint8_t*)op->buf, op->req.rw.len, 0)) + if (!rdr.read((uint8_t*)op->buf, op->req.rw.len, cl->proto_csum_status == MSGR_CSUM_GCM ? RDR_GCM : 0)) return false; } else if (op->req.hdr.opcode == OSD_OP_SHOW_CONFIG) @@ -973,7 +961,7 @@ switched_type: if (op->reply.hdr.retval > 0) { for (int i = 0; i < op->iov.count; i++) - if (!rdr.read((uint8_t*)op->iov.buf[i].iov_base, op->iov.buf[i].iov_len, 0)) + if (!rdr.read((uint8_t*)op->iov.buf[i].iov_base, op->iov.buf[i].iov_len, (cl->proto_csum_status == MSGR_CSUM_GCM ? RDR_GCM : 0))) return false; } } @@ -987,7 +975,7 @@ switched_type: if (op->reply.hdr.retval > 0) { for (int i = 0; i < op->iov.count; i++) - if (!rdr.read((uint8_t*)op->iov.buf[i].iov_base, op->iov.buf[i].iov_len, (op->enc ? RDR_XTS : 0))) + if (!rdr.read((uint8_t*)op->iov.buf[i].iov_base, op->iov.buf[i].iov_len, (op->enc ? RDR_XTS : 0) | (cl->proto_csum_status == MSGR_CSUM_GCM ? RDR_GCM : 0))) return false; } } diff --git a/src/client/msgr_send.cpp b/src/client/msgr_send.cpp index 306dfa0d..69fc4b2f 100644 --- a/src/client/msgr_send.cpp +++ b/src/client/msgr_send.cpp @@ -15,6 +15,8 @@ #define WR_XTS 2 #define WR_NO_CSUM 4 +#define GCM_TMP_BUF_SIZE 4096 + class msgr_op_writer_t { public: @@ -180,28 +182,11 @@ public: from -= src_len; return true; } - if (!(flags & WR_GCM)) + if (flags & WR_XTS) { - if (flags & WR_XTS) - { - msgr->op_encrypted_copy_buf(cl, curbuf, bufsize, src, src_len, from, done); - } - else - { - size_t n = src_len-from; - if (n > bufsize-done) - n = bufsize-done; - if (!n) - return false; - if (cl->write_csum_state && !(flags & WR_NO_CSUM)) - XXH3_64bits_update(cl->write_csum_state, src+from, n); - memcpy(curbuf+done, src+from, n); - done += n; - cl->write_op_pos += n; - from += n; - } + msgr->op_encrypted_copy_buf(cl, curbuf, bufsize, src, src_len, from, done); } - else + else if (flags & WR_GCM) { size_t n = src_len-from; if (n > bufsize-done) @@ -227,6 +212,20 @@ public: cl->write_op_pos += n; from += n; } + else + { + size_t n = src_len-from; + if (n > bufsize-done) + n = bufsize-done; + if (!n) + return false; + if (cl->write_csum_state && !(flags & WR_NO_CSUM)) + XXH3_64bits_update(cl->write_csum_state, src+from, n); + memcpy(curbuf+done, src+from, n); + done += n; + cl->write_op_pos += n; + from += n; + } if (from < src_len) return false; from = 0; @@ -297,63 +296,49 @@ class get_op_writer_t: public msgr_op_writer_t osd_client_t* cl; size_t from; size_t done; + size_t op_enc; size_t enc_size; size_t done_enc; + uint8_t *enc_buf; public: get_op_writer_t(osd_messenger_t* msgr, osd_client_t* cl, uint8_t*, size_t): - msgr(msgr), cl(cl), from(cl->write_op_pos), done(0), enc_size(0), done_enc(0) + msgr(msgr), cl(cl), from(cl->write_op_pos), done(0), enc_size(0), done_enc(0), enc_buf(NULL) { } - static void ssl_extend_buf(osd_client_t *cl, size_t more = 0) - { - size_t min_cap = cl->ssl_out_buf_size*2; - if (min_cap < cl->ssl_out_buf_size+more) - min_cap = cl->ssl_out_buf_size+more; - if (min_cap < 16384) - min_cap = 16384; - if (cl->ssl_out_buf_cap < min_cap) - { - uintptr_t old_buf = (uintptr_t)cl->ssl_out_buf; - uintptr_t old_end = old_buf + cl->ssl_out_buf_cap; - cl->ssl_out_buf = (uint8_t*)realloc_or_die(cl->ssl_out_buf, min_cap); - cl->ssl_out_buf_cap = min_cap; - for (auto & iov: cl->send_list) - { - if ((uintptr_t)iov.iov_base >= old_buf && (uintptr_t)iov.iov_base < old_end) - iov.iov_base = cl->ssl_out_buf + ((uintptr_t)iov.iov_base - old_buf); - } - } - } - - static void send_out_buf(osd_client_t *cl, size_t n) - { - if (cl->send_list.size() > 0) - { - iovec& last = cl->send_list.back(); - if (last.iov_base+last.iov_len == cl->ssl_out_buf+cl->ssl_out_buf_size) - { - last.iov_len += n; - cl->ssl_out_buf_size += n; - return; - } - } - cl->send_list.push_back((iovec){ .iov_base = cl->ssl_out_buf+cl->ssl_out_buf_size, .iov_len = n }); - cl->ssl_out_buf_size += n; - } - void reset() { + op_enc = 0; from = cl->write_op_pos; - enc_size = 0; - done_enc = 0; if (cl->gcm_enabled) { gcm_op_writer_t::init_ctx(msgr, cl); } } + void extend_tmp(size_t n) + { + if (!enc_buf || done_enc + n > enc_size) + { + enc_size = n < GCM_TMP_BUF_SIZE ? GCM_TMP_BUF_SIZE : n; + enc_buf = (uint8_t*)malloc_or_die(enc_size); + done_enc = 0; + assert(!((size_t)enc_buf & 7)); + cl->send_free_ops.push_back((osd_op_t*)((size_t)enc_buf | 1)); + } + } + + void send_tmp(size_t n) + { + if (cl->send_list.size() && cl->send_list.back().iov_base == (enc_buf + done_enc)) + cl->send_list.back().iov_len += n; + else + cl->send_list.push_back((iovec){ .iov_base = enc_buf + done_enc, .iov_len = n }); + done += n; + done_enc += n; + } + bool write(uint8_t *src, size_t src_len, int flags) override { if (from >= src_len) @@ -362,63 +347,54 @@ public: from -= src_len; return true; } - if (cl->send_list.size() >= IOV_MAX) + if (cl->send_list.size() >= IOV_MAX-1) { + // Make sure tag always fits return false; } - if (flags & WR_GCM) - { - if (cl->gcm_enabled) - { - // Encrypt data to client's temporary output buffer (all at once) - size_t n = src_len-from; - ssl_extend_buf(cl, n); -#ifdef WITH_ISAL_CRYPTO - int r = isal_aes_gcm_enc_256_update(&cl->my_key_isal, cl->enc_ctx, cl->ssl_out_buf+cl->ssl_out_buf_size, src+from, n); - assert(!r); -#else - int actual_out; - if (EVP_EncryptUpdate(cl->enc_ctx, cl->ssl_out_buf+cl->ssl_out_buf_size, &actual_out, src+from, n) != 1) - { - fprintf(stderr, "EncryptUpdate error: "); - ERR_print_errors_fp(stderr); - abort(); - } - assert(actual_out == n); -#endif - if (cl->write_csum_state && !(flags & WR_NO_CSUM)) - XXH3_64bits_update(cl->write_csum_state, src+from, n); - send_out_buf(cl, n); - done += n; - cl->write_op_pos += n; - from += n; - if (from < src_len) - return false; - from = 0; - return true; - } - } if (flags & WR_XTS) { - if (!cl->write_op->enc_buf) + // Allocate a temporary buffer and encrypt data to it + if (!op_enc) { - if (cl->send_list.size() >= IOV_MAX-1) - { - // Make sure that 1 encrypted buffer and 1 checksum fits - return false; - } - // No way except than to allocate a temporary buffer and encrypt data to it assert(cl->write_op->req.hdr.opcode == OSD_OP_WRITE); - enc_size = cl->write_op->req.rw.len - from + (from % 16); - assert(enc_size > 0); - cl->write_op->enc_buf = (uint8_t*)malloc_or_die(enc_size); - cl->send_list.push_back((iovec){ .iov_base = cl->write_op->enc_buf, .iov_len = enc_size }); - done += enc_size; + op_enc = cl->write_op->req.rw.len - from + (from % 16); + assert(op_enc > 0); + extend_tmp(op_enc); } - assert(enc_size > 0); - msgr->op_encrypted_copy_buf(cl, cl->write_op->enc_buf, enc_size, src, src_len, from, done_enc); + size_t new_done = done_enc; + msgr->op_encrypted_copy_buf(cl, enc_buf, enc_size, src, src_len, from, new_done); + send_tmp(new_done-done_enc); assert(from == src_len); } + else if ((flags & WR_GCM) && cl->gcm_enabled) + { + // Allocate a temporary buffer and encrypt data to it + size_t n = src_len-from; + extend_tmp(n); +#ifdef WITH_ISAL_CRYPTO + int r = isal_aes_gcm_enc_256_update(&cl->my_key_isal, cl->enc_ctx, enc_buf+done_enc, src+from, n); + assert(!r); +#else + int actual_out; + if (EVP_EncryptUpdate(cl->enc_ctx, enc_buf+done_enc, &actual_out, src+from, n) != 1) + { + fprintf(stderr, "EncryptUpdate error: "); + ERR_print_errors_fp(stderr); + abort(); + } + assert(actual_out == n); +#endif + if (cl->write_csum_state && !(flags & WR_NO_CSUM)) + XXH3_64bits_update(cl->write_csum_state, src+from, n); + send_tmp(n); + cl->write_op_pos += n; + from += n; + if (from < src_len) + return false; + from = 0; + return true; + } else { if (cl->write_csum_state && !(flags & WR_NO_CSUM)) @@ -435,13 +411,10 @@ public: { if (cl->enc_ctx) { - if (cl->send_list.size() >= IOV_MAX) - return false; // Tag is 16 bytes - ssl_extend_buf(cl, 16); - gcm_op_writer_t::write_tag_to(msgr, cl, cl->ssl_out_buf+cl->ssl_out_buf_size); - send_out_buf(cl, 16); - done += 16; + extend_tmp(16); + gcm_op_writer_t::write_tag_to(msgr, cl, enc_buf + done_enc); + send_tmp(16); gcm_op_writer_t::free_ctx(msgr, cl); } return true; @@ -527,14 +500,15 @@ bool osd_messenger_t::try_send(osd_client_t *cl) if (cl->hs) { // Send handshake message - if (cl->hs->get_out().size()) + if (cl->hs->out_size()) { - get_op_writer_t::ssl_extend_buf(cl, cl->hs->get_out().size()); - memcpy(cl->ssl_out_buf+cl->ssl_out_buf_size, cl->hs->get_out().data(), cl->hs->get_out().size()); - get_op_writer_t::send_out_buf(cl, cl->hs->get_out().size()); - cl->hs->get_out().clear(); + uint8_t *out = cl->hs->get_out(); + cl->send_list.push_back((iovec){ .iov_base = out, .iov_len = cl->hs->out_size() }); + assert(!((size_t)out & 7)); + cl->send_free_ops.push_back((osd_op_t*)((size_t)out | 1)); + cl->hs->reset_out(); } - if (!cl->hs->get_out().size() && cl->hs->done()) + if (!cl->hs->out_size() && cl->hs->done()) { delete cl->hs; cl->hs = NULL; @@ -621,13 +595,13 @@ size_t osd_messenger_t::copy_ops_to(osd_client_t *cl, uint8_t *dst, size_t dst_l { // Send handshake message size_t n = 0; - if (cl->hs->get_out().size()) + if (cl->hs->out_size()) { - n = cl->hs->get_out().size() < dst_len ? cl->hs->get_out().size() : dst_len; - memcpy(dst, cl->hs->get_out().data(), n); - cl->hs->get_out().erase(cl->hs->get_out().begin(), cl->hs->get_out().begin() + n); + n = cl->hs->out_size() < dst_len ? cl->hs->out_size() : dst_len; + memcpy(dst, cl->hs->get_out(), n); + cl->hs->eat_out(n); } - if (!cl->hs->get_out().size() && cl->hs->done()) + if (!cl->hs->out_size() && cl->hs->done()) { delete cl->hs; cl->hs = NULL; @@ -750,24 +724,14 @@ void osd_messenger_t::handle_send(int result, bool prev, bool more, osd_client_t for (auto op: cl->send_free_ops) { if (more) - { - assert(!((size_t)op & 7)); cl->zc_free_list.push_back(op); - } - else + else if (!((size_t)op & 7)) delete op; + else + free((void*)((size_t)op & ~(size_t)7)); } if (more) - { - if (cl->ssl_out_buf_size) - { - cl->zc_free_list.push_back((osd_op_t*)((size_t)cl->ssl_out_buf | 1)); - cl->ssl_out_buf = NULL; - cl->ssl_out_buf_cap = 0; - } cl->zc_free_list.push_back(NULL); // end marker - } - cl->ssl_out_buf_size = 0; cl->send_free_ops.clear(); cl->write_state = 0; if (cl->write_op || cl->write_ops.size()) @@ -875,7 +839,7 @@ bool osd_messenger_t::op_write_to(osd_client_t *cl, msgr_op_writer_t & wr) for (int i = 0; i < cl->write_op->iov.count; i++) { auto & iov = cl->write_op->iov.buf[i]; - if (!wr.write((uint8_t*)iov.iov_base, iov.iov_len, (op->enc ? WR_XTS : 0))) + if (!wr.write((uint8_t*)iov.iov_base, iov.iov_len, (op->enc ? WR_XTS : 0) | (cl->proto_csum_status == MSGR_CSUM_GCM ? WR_GCM : 0))) return false; } } diff --git a/src/client/msgr_stop.cpp b/src/client/msgr_stop.cpp index d61236d9..82a68922 100644 --- a/src/client/msgr_stop.cpp +++ b/src/client/msgr_stop.cpp @@ -202,7 +202,10 @@ osd_client_t::~osd_client_t() { if (op) { - delete op; + if (!((size_t)op & 7)) + delete op; + else + free((void*)((size_t)op & ~(size_t)7)); } } for (osd_op_t *op: zc_free_list) @@ -243,11 +246,6 @@ osd_client_t::~osd_client_t() #endif dec_ctx = NULL; } - if (ssl_out_buf) - { - free(ssl_out_buf); - ssl_out_buf = NULL; - } if (hs) { delete hs; diff --git a/src/osd/osd_secondary.cpp b/src/osd/osd_secondary.cpp index e4355cf2..de35787e 100644 --- a/src/osd/osd_secondary.cpp +++ b/src/osd/osd_secondary.cpp @@ -376,14 +376,23 @@ void osd_t::exec_show_config(osd_op_t *cur_op) if (msgr.use_proto_checksums) { auto peer_csums = req_json["features"]["proto_checksums"].uint64_value(); - if (peer_csums == MSGR_CSUM_FULL || peer_csums == MSGR_CSUM_PAYLOAD) + if (peer_csums == MSGR_CSUM_FULL || peer_csums == MSGR_CSUM_PAYLOAD || + cl->gcm_enabled && peer_csums == MSGR_CSUM_GCM) { - if (msgr.use_proto_checksums == MSGR_CSUM_FULL && peer_csums == MSGR_CSUM_FULL) + if (msgr.use_proto_checksums == MSGR_CSUM_GCM && peer_csums == MSGR_CSUM_GCM) + cl->proto_csum_status = MSGR_CSUM_GCM|MSGR_CSUM_NEG; + else if (msgr.use_proto_checksums == MSGR_CSUM_FULL && peer_csums == MSGR_CSUM_FULL) cl->proto_csum_status = MSGR_CSUM_FULL|MSGR_CSUM_NEG; else cl->proto_csum_status = MSGR_CSUM_PAYLOAD|MSGR_CSUM_NEG; features["proto_checksums"] = msgr.use_proto_checksums; } + if (peer_csums < msgr.force_proto_checksums) + { + fprintf(stderr, "Error: Client %ju use_proto_checksums security level is lower than force_proto_checksums\n", cl->client_id); + msgr.stop_client(cl->client_id); + return; + } } // Expose sensitive configuration values so peers can check them json11::Json::object wire_config = json11::Json::object { diff --git a/src/test/test_cluster_client.cpp b/src/test/test_cluster_client.cpp index cd0ef7ef..96803079 100644 --- a/src/test/test_cluster_client.cpp +++ b/src/test/test_cluster_client.cpp @@ -663,11 +663,12 @@ void test_msgr_encrypt() uint8_t *crypt2 = (uint8_t*)malloc_or_die(sz); uint8_t *key = (uint8_t*)malloc_or_die(64); RAND_bytes(key, 64); + osd_client_t cl; // Basic encrypt+decrypt and also get reference data auto enc = new op_aes_xts_encrypt_t(); - enc->start(key, 4096 * 113, 4096); + enc->start(&cl, key, 4096 * 113, 4096); size_t in_pos = 0; size_t out_pos = 0; while (out_pos < sz) @@ -676,7 +677,7 @@ void test_msgr_encrypt() } auto dec = new op_aes_xts_decrypt_t(); - dec->start(&key, 1, NULL, 4096 * 113, 4096); + dec->start(&cl, &key, 1, NULL, 4096 * 113, 4096); in_pos = out_pos = 0; while (out_pos < sz) { @@ -687,7 +688,7 @@ void test_msgr_encrypt() // Insufficient output encrypt printf("...insufficient output encrypt\n"); - enc->start(key, 4096 * 114, 4096); + enc->start(&cl, key, 4096 * 114, 4096); in_pos = out_pos = 0; enc->update(src+4096, 4096, crypt2, 4095, in_pos, out_pos); assert(in_pos == 4095); @@ -699,7 +700,7 @@ void test_msgr_encrypt() // Fragmented encrypt printf("...fragmented encrypt\n"); - enc->start(key, 4096 * 114, 4096); + enc->start(&cl, key, 4096 * 114, 4096); in_pos = out_pos = 0; enc->update(src+4096, 2000, crypt2, 4095, in_pos, out_pos); assert(in_pos == 2000); @@ -712,7 +713,7 @@ void test_msgr_encrypt() // Fragmented decrypt // Input: 1000 + 2000 + 3000 + 2192, output: 500 + 3000 + 1000 + 3000 + 692 printf("...fragmented decrypt\n"); - dec->start(&key, 1, NULL, 4096 * 114, 4096); + dec->start(&cl, &key, 1, NULL, 4096 * 114, 4096); in_pos = out_pos = 0; dec->update(crypt+4096, 1000, decrypt, 500, in_pos, out_pos); assert(in_pos == 1000); @@ -746,7 +747,7 @@ void test_msgr_encrypt() // Extra size decrypt // Input: 8192, output: 4096 printf("...extra size decrypt\n"); - dec->start(&key, 1, NULL, 4096 * 114, 4096); + dec->start(&cl, &key, 1, NULL, 4096 * 114, 4096); in_pos = out_pos = 0; dec->update(crypt+4096, 8192, decrypt, 4096, in_pos, out_pos); assert(in_pos == 4096); @@ -776,6 +777,7 @@ void test_msgr_decrypt_chain() RAND_bytes(key, 64); uint8_t *key2 = (uint8_t*)malloc_or_die(64); RAND_bytes(key2, 64); + osd_client_t cl; // Chained decryption with multiple keys @@ -783,17 +785,17 @@ void test_msgr_decrypt_chain() size_t in_pos = 0, out_pos = 0; auto enc = new op_aes_xts_encrypt_t(); // block 1 with key1 - enc->start(key, 4096 * 113, 4096); + enc->start(&cl, key, 4096 * 113, 4096); enc->update(src, 4096, crypt, 4096, in_pos, out_pos); assert(in_pos == 4096 && out_pos == 4096); // block 2 as plain memcpy(crypt + 4096, src + 4096, 4096); // block 3 with key2 - enc->start(key2, 4096 * 115, 4096); + enc->start(&cl, key2, 4096 * 115, 4096); enc->update(src + 2*4096, 4096, crypt + 2*4096, 4096, in_pos, out_pos); assert(in_pos == 2*4096 && out_pos == 2*4096); // block 4 again with key1 - enc->start(key, 4096 * 116, 4096); + enc->start(&cl, key, 4096 * 116, 4096); enc->update(src + 3*4096, 4096, crypt + 3*4096, 4096, in_pos, out_pos); assert(in_pos == 3*4096 && out_pos == 3*4096); @@ -801,7 +803,7 @@ void test_msgr_decrypt_chain() uint8_t* keys[3] = { key, key2, NULL }; uint8_t chain_info[4] = { 0, 2, 1, 0 }; auto dec = new op_aes_xts_decrypt_t(); - dec->start(keys, 3, chain_info, 4096 * 113, 4096); + dec->start(&cl, keys, 3, chain_info, 4096 * 113, 4096); in_pos = out_pos = 0; while (out_pos < sz) { diff --git a/tests/run_tests.sh b/tests/run_tests.sh index afa2d6a6..be4f9dcd 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -63,6 +63,7 @@ OLD=1 ./test_move_reappear.sh ./test_snapshot_chain.sh SCHEME=ec ./test_snapshot_chain.sh ENCRYPTED=1 ./test_snapshot_chain.sh +TEST_NAME=enc_gcm ENCRYPTED=1 VITASTOR_CFG=',"proto_checksums":"gcm"' ./test_snapshot_chain.sh OLD=1 ./test_snapshot_chain.sh OLD=1 SCHEME=ec ./test_snapshot_chain.sh