From e7d72ae7f6a6995a21d743389426a963429a1fff Mon Sep 17 00:00:00 2001 From: mkaruza Date: Sat, 10 Nov 2018 11:07:52 +0100 Subject: [PATCH] codership/mariadb-wsrep#27 Galera cache encryption * Created interface class for encryption support * Implemented function for setting enc key to provider, callback function for encryption/decryption --- dbsim/db_server_state.hpp | 1 + include/wsrep/encryption_service.hpp | 67 ++++++++++++++++++++++++++ include/wsrep/provider.hpp | 2 +- include/wsrep/server_state.hpp | 24 ++++++++++ src/server_state.cpp | 24 +++++++--- src/wsrep_provider_v26.cpp | 70 ++++++++++++++++++++++++---- src/wsrep_provider_v26.hpp | 2 +- test/mock_provider.hpp | 3 ++ test/mock_server_state.hpp | 2 +- 9 files changed, 178 insertions(+), 17 deletions(-) create mode 100644 include/wsrep/encryption_service.hpp diff --git a/dbsim/db_server_state.hpp b/dbsim/db_server_state.hpp index 12bb9e3..49d4499 100644 --- a/dbsim/db_server_state.hpp +++ b/dbsim/db_server_state.hpp @@ -40,6 +40,7 @@ namespace db mutex_, cond_, server_service, + nullptr, name, "", address, diff --git a/include/wsrep/encryption_service.hpp b/include/wsrep/encryption_service.hpp new file mode 100644 index 0000000..0efcde0 --- /dev/null +++ b/include/wsrep/encryption_service.hpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2019 Codership Oy + * + * This file is part of wsrep-lib. + * + * Wsrep-lib is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Wsrep-lib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wsrep-lib. If not, see . + */ + +#ifndef WSREP_ENCRYPTION_SERVICE_HPP +#define WSREP_ENCRYPTION_SERVICE_HPP + +#include "buffer.hpp" + +namespace wsrep +{ + /** + * Encryption service. + */ + class encryption_service + { + public: + + virtual ~encryption_service() { } + + /** + * Encryption/decryption callback. Can be NULL for no encryption. + * + * @param ctx Encryption context + * @param key Key used in encryption/decryption + * @param iv IV vector + * @param input Input data buffer + * @param output An output buffer, must be at least the size of the input + * data plus unwritten bytes from the previous call(s). + * @param encrypt Flag used to either encrypt or decrypt data + * @param last true if this is the last buffer to encrypt/decrypt + * + * @return Number of bytes written to output or a negative error code. + */ + virtual int do_crypt(void** ctx, + wsrep::const_buffer& key, + const char (*iv)[32], + wsrep::const_buffer& input, + void* output, + bool encrypt, + bool last) = 0; + + /** + * Is encryption enabled on server. + * + * @return True if encryption is enabled. False otherwise + */ + virtual bool encryption_enabled() = 0; + }; +} + +#endif // WSREP_ENCRYPTION_SERVICE_HPP diff --git a/include/wsrep/provider.hpp b/include/wsrep/provider.hpp index 38bf631..2cac898 100644 --- a/include/wsrep/provider.hpp +++ b/include/wsrep/provider.hpp @@ -341,7 +341,7 @@ namespace wsrep virtual wsrep::gtid last_committed_gtid() const = 0; virtual int sst_sent(const wsrep::gtid&, int) = 0; virtual int sst_received(const wsrep::gtid&, int) = 0; - + virtual int enc_set_key(const wsrep::const_buffer& key) = 0; virtual std::vector status() const = 0; virtual void reset_status() = 0; diff --git a/include/wsrep/server_state.hpp b/include/wsrep/server_state.hpp index 0a359a4..e93610f 100644 --- a/include/wsrep/server_state.hpp +++ b/include/wsrep/server_state.hpp @@ -104,6 +104,7 @@ namespace wsrep class const_buffer; class server_service; class client_service; + class encryption_service; /** @class Server Context * @@ -180,8 +181,11 @@ namespace wsrep virtual ~server_state(); + wsrep::encryption_service* encryption_service() + { return encryption_service_; } wsrep::server_service& server_service() { return server_service_; } + /** * Return human readable server name. * @@ -369,6 +373,21 @@ namespace wsrep enum wsrep::provider::status wait_for_gtid(const wsrep::gtid&, int timeout) const; + /** + * Set encryption key + * + * @param key Encryption key + * + * @return Zero on success, non-zero on failure. + */ + int set_encryption_key(std::vector& key); + + /** + * Return encryption key. + */ + const std::vector& get_encryption_key() const + { return encryption_key_; } + /** * Perform a causal read in the cluster. After the call returns, * all the causally preceding write sets have been committed @@ -553,6 +572,7 @@ namespace wsrep server_state(wsrep::mutex& mutex, wsrep::condition_variable& cond, wsrep::server_service& server_service, + wsrep::encryption_service* encryption_service, const std::string& name, const std::string& incoming_address, const std::string& address, @@ -563,6 +583,7 @@ namespace wsrep : mutex_(mutex) , cond_(cond) , server_service_(server_service) + , encryption_service_(encryption_service) , state_(s_disconnected) , state_hist_() , state_waiters_(n_states_) @@ -584,6 +605,7 @@ namespace wsrep , incoming_address_(incoming_address) , address_(address) , working_dir_(working_dir) + , encryption_key_() , max_protocol_version_(max_protocol_version) , rollback_mode_(rollback_mode) , connected_gtid_() @@ -631,6 +653,7 @@ namespace wsrep wsrep::mutex& mutex_; wsrep::condition_variable& cond_; wsrep::server_service& server_service_; + wsrep::encryption_service* encryption_service_; enum state state_; std::vector state_hist_; mutable std::vector state_waiters_; @@ -672,6 +695,7 @@ namespace wsrep std::string incoming_address_; std::string address_; std::string working_dir_; + std::vector encryption_key_; int max_protocol_version_; enum rollback_mode rollback_mode_; wsrep::gtid connected_gtid_; diff --git a/src/server_state.cpp b/src/server_state.cpp index 9d76b62..5e87846 100644 --- a/src/server_state.cpp +++ b/src/server_state.cpp @@ -337,12 +337,12 @@ static int apply_toi(wsrep::provider& provider, int wsrep::server_state::load_provider(const std::string& provider_spec, const std::string& provider_options) { - wsrep::log_info() << "Loading provider " - << provider_spec - << "initial position: " - << initial_position_; - provider_ = wsrep::provider::make_provider( - *this, provider_spec, provider_options); + wsrep::log_info() << "Loading provider " << provider_spec + << "initial position: " << initial_position_; + + provider_ = wsrep::provider::make_provider(*this, + provider_spec, + provider_options); return (provider_ ? 0 : 1); } @@ -630,6 +630,18 @@ wsrep::server_state::wait_for_gtid(const wsrep::gtid& gtid, int timeout) return provider().wait_for_gtid(gtid, timeout); } +int +wsrep::server_state::set_encryption_key(std::vector& key) +{ + encryption_key_ = key; + if (state_ != s_disconnected) + { + return provider_->enc_set_key(wsrep::const_buffer(encryption_key_.data(), + encryption_key_.size())); + } + return 0; +} + std::pair wsrep::server_state::causal_read(int timeout) const { diff --git a/src/wsrep_provider_v26.cpp b/src/wsrep_provider_v26.cpp index a38c523..c49a5c6 100644 --- a/src/wsrep_provider_v26.cpp +++ b/src/wsrep_provider_v26.cpp @@ -19,6 +19,7 @@ #include "wsrep_provider_v26.hpp" +#include "wsrep/encryption_service.hpp" #include "wsrep/server_state.hpp" #include "wsrep/high_priority_service.hpp" #include "wsrep/view.hpp" @@ -421,14 +422,42 @@ namespace } } - int encrypt_cb(void* /* app ctx */, - wsrep_enc_ctx_t* /*ctx*/, - const wsrep_buf_t* /*input*/, - void* /*output*/, - wsrep_enc_direction_t /*direction*/, - bool /*final*/) + int encrypt_cb(void* app_ctx, + wsrep_enc_ctx_t* enc_ctx, + const wsrep_buf_t* input, + void* output, + wsrep_enc_direction_t direction, + bool last) { - return 0; + assert(app_ctx); + wsrep::server_state& server_state( + *static_cast(app_ctx)); + + assert(server_state.encryption_service()); + if (server_state.encryption_service() == 0) + { + wsrep::log_error() << "Encryption service not defined in encrypt_cb()"; + return -1; + } + + wsrep::const_buffer key(enc_ctx->key->ptr, enc_ctx->key->len); + wsrep::const_buffer in(input->ptr, input->len); + try + { + return server_state.encryption_service()->do_crypt(&enc_ctx->ctx, + key, + enc_ctx->iv, + in, + output, + direction == WSREP_ENC, + last); + } + catch (const wsrep::runtime_error& e) + { + free(enc_ctx->ctx); + // Return negative value in case of callback error + return -1; + } } wsrep_cb_status_t apply_cb(void* ctx, @@ -549,6 +578,8 @@ wsrep::wsrep_provider_v26::wsrep_provider_v26( , wsrep_() { wsrep_gtid_t state_id; + bool encryption_enabled = server_state.encryption_service() && + server_state.encryption_service()->encryption_enabled(); std::memcpy(state_id.uuid.data, server_state.initial_position().id().data(), sizeof(state_id.uuid.data)); @@ -568,7 +599,7 @@ wsrep::wsrep_provider_v26::wsrep_provider_v26( init_args.connected_cb = &connected_cb; init_args.view_cb = &view_cb; init_args.sst_request_cb = &sst_request_cb; - init_args.encrypt_cb = &encrypt_cb; + init_args.encrypt_cb = encryption_enabled ? encrypt_cb : NULL; init_args.apply_cb = &apply_cb; init_args.unordered_cb = 0; init_args.sst_donate_cb = &sst_donate_cb; @@ -582,6 +613,19 @@ wsrep::wsrep_provider_v26::wsrep_provider_v26( { throw wsrep::runtime_error("Failed to initialize wsrep provider"); } + + if (encryption_enabled) + { + const std::vector& key = server_state.get_encryption_key(); + if (key.size()) + { + wsrep::const_buffer const_key(key.data(), key.size()); + if(enc_set_key(const_key)) + { + throw wsrep::runtime_error("Failed to set encryption key"); + } + } + } } wsrep::wsrep_provider_v26::~wsrep_provider_v26() @@ -856,6 +900,16 @@ int wsrep::wsrep_provider_v26::sst_received(const wsrep::gtid& gtid, int err) return 0; } +int wsrep::wsrep_provider_v26::enc_set_key(const wsrep::const_buffer& key) +{ + wsrep_enc_key_t enc_key = {key.data(), key.size()}; + if (wsrep_->enc_set_key(wsrep_, &enc_key) != WSREP_OK) + { + return 1; + } + return 0; +} + std::vector wsrep::wsrep_provider_v26::status() const { diff --git a/src/wsrep_provider_v26.hpp b/src/wsrep_provider_v26.hpp index c2a706b..695cd40 100644 --- a/src/wsrep_provider_v26.hpp +++ b/src/wsrep_provider_v26.hpp @@ -78,7 +78,7 @@ namespace wsrep wsrep::gtid last_committed_gtid() const; int sst_sent(const wsrep::gtid&,int); int sst_received(const wsrep::gtid& gtid, int); - + int enc_set_key(const wsrep::const_buffer& key); std::vector status() const; void reset_status(); std::string options() const; diff --git a/test/mock_provider.hpp b/test/mock_provider.hpp index 9c4d94b..7a27671 100644 --- a/test/mock_provider.hpp +++ b/test/mock_provider.hpp @@ -252,6 +252,9 @@ namespace wsrep int sst_sent(const wsrep::gtid&, int) WSREP_OVERRIDE { return 0; } int sst_received(const wsrep::gtid&, int) WSREP_OVERRIDE { return 0; } + int enc_set_key(const wsrep::const_buffer&) WSREP_OVERRIDE + { return 0; } + std::vector status() const WSREP_OVERRIDE { return std::vector(); diff --git a/test/mock_server_state.hpp b/test/mock_server_state.hpp index 4283dab..fab755d 100644 --- a/test/mock_server_state.hpp +++ b/test/mock_server_state.hpp @@ -231,7 +231,7 @@ namespace wsrep mock_server_state(const std::string& name, enum wsrep::server_state::rollback_mode rollback_mode, wsrep::server_service& server_service) - : wsrep::server_state(mutex_, cond_, server_service, + : wsrep::server_state(mutex_, cond_, server_service, NULL, name, "", "", "./", wsrep::gtid::undefined(), 1,