From: Radoslaw Zarzynski Date: Sun, 10 Feb 2019 23:31:49 +0000 (+0100) Subject: auth, msg/async, v2: drop AuthStreamHandler and AES128GCM_StreamHandler. X-Git-Tag: v14.1.1~157^2~42 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=0ac6876c04fbe275530c2b29ca61e32a77635495;p=ceph.git auth, msg/async, v2: drop AuthStreamHandler and AES128GCM_StreamHandler. Signed-off-by: Radoslaw Zarzynski --- diff --git a/src/auth/AuthSessionHandler.cc b/src/auth/AuthSessionHandler.cc index 54fff2740720..5835396075b4 100644 --- a/src/auth/AuthSessionHandler.cc +++ b/src/auth/AuthSessionHandler.cc @@ -55,235 +55,3 @@ AuthSessionHandler *get_auth_session_handler( } } - -#ifdef USE_OPENSSL -# include -#endif - -// http://www.mindspring.com/~dmcgrew/gcm-nist-6.pdf -// https://www.openssl.org/docs/man1.0.2/crypto/EVP_aes_128_gcm.html#GCM-mode -// https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption -class AES128GCM_StreamHandler : public AuthStreamHandler { - CephContext* const cct; - std::unique_ptr ectx; - - static constexpr const std::size_t AES_KEY_LEN{16}; - static constexpr const std::size_t STREAM_AES_IV_LEN{16}; - static constexpr const std::size_t STREAM_GCM_TAG_LEN{16}; - static constexpr const std::size_t AES_BLOCK_LEN{16}; - - std::array connection_secret; - - // using GCC's "Tetra Integer" mode here - ceph::uint128_t nonce; - static_assert(sizeof(nonce) == STREAM_AES_IV_LEN); - -public: - AES128GCM_StreamHandler(CephContext* const cct, - const AuthConnectionMeta& auth_meta, - const ceph::uint128_t& nonce) - : cct(cct), - ectx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free), - nonce(nonce) { - ceph_assert_always(auth_meta.connection_secret.length() >= AES_KEY_LEN); - ceph_assert_always(ectx); - - std::copy_n(std::cbegin(auth_meta.connection_secret), AES_KEY_LEN, - std::begin(connection_secret)); - //EVP_CIPHER_CTX_reset(ectx.get()); - } - - ~AES128GCM_StreamHandler() override { - memset(&nonce, 0, sizeof(nonce)); - //connection_secret.zero(); - } - - std::size_t calculate_padded_size(const std::size_t length) { - // we need to take into account the PKCS#7 padding. There *always* will - // be at least one byte of padding. This stays even to input aligned to - // AES_BLOCK_LEN. Otherwise we would face ambiguities during decryption. - // To exemplify: - // length := 10 -> p2align(10, 16) + 16 == 16 (06 bytes for padding), - // length := 16 -> p2align(16, 16) + 16 == 32 (16 bytes for padding). - // - // Technically padding will be added by OpenSSL but its format and even - // presence is a part of the public interface, I believe. - return p2align(length, AES_BLOCK_LEN) + AES_BLOCK_LEN; - } - - std::size_t calculate_payload_size(const std::size_t length) override { - // as we're doing *authenticated encryption* additional space is needed - // to store Auth Tag. OpenSSL defaults this to 96 bits (12 bytes). - const std::size_t authenticated_and_encrypted_size = \ - calculate_padded_size(length) + STREAM_GCM_TAG_LEN; - return authenticated_and_encrypted_size; - } - - void authenticated_encrypt(ceph::bufferlist& payload) override; - void authenticated_decrypt(char* payload, uint32_t& length) override; -}; - -void AES128GCM_StreamHandler::authenticated_encrypt(ceph::bufferlist& payload) -{ - if (1 != EVP_EncryptInit_ex(ectx.get(), EVP_aes_128_gcm(), - nullptr, nullptr, nullptr)) { - throw std::runtime_error("EVP_EncryptInit_ex failed"); - } - - if (1 != EVP_CIPHER_CTX_ctrl(ectx.get(), EVP_CTRL_GCM_SET_IVLEN, - STREAM_AES_IV_LEN, nullptr) ) { - throw std::runtime_error("EVP_CIPHER_CTX_ctrl failed"); - } - - if(1 != EVP_EncryptInit_ex(ectx.get(), nullptr, nullptr, - reinterpret_cast(connection_secret.data()), - reinterpret_cast(&nonce))) { - throw std::runtime_error("EVP_EncryptInit_ex failed"); - } - - // TODO: consider in-place transformata - auto out_tmp = \ - ceph::buffer::ptr_node::create(calculate_payload_size(payload.length())); - - // append necessary padding accordingly to PKCS#7 - { - const auto padding_size = \ - calculate_padded_size(payload.length()) - payload.length(); - auto filler = payload.append_hole(padding_size); - ::memset(filler.c_str(), static_cast(padding_size), padding_size); - } - - int update_len = 0; - if(1 != EVP_EncryptUpdate(ectx.get(), - reinterpret_cast(out_tmp->c_str()), - &update_len, - reinterpret_cast(payload.c_str()), - payload.length())) { - throw std::runtime_error("EVP_EncryptUpdate failed"); - } - - int final_len = 0; - if(1 != EVP_EncryptFinal_ex(ectx.get(), - reinterpret_cast(out_tmp->c_str() + update_len), - &final_len)) { - throw std::runtime_error("EVP_EncryptFinal_ex failed"); - } - - if(1 != EVP_CIPHER_CTX_ctrl(ectx.get(), - EVP_CTRL_GCM_GET_TAG, STREAM_GCM_TAG_LEN, - out_tmp->c_str() + update_len + final_len)) { - throw std::runtime_error("EVP_CIPHER_CTX_ctrl failed"); - } - -#if 0 - if (1 != EVP_CIPHER_CTX_cleanup(ectx.get())) { - throw std::runtime_error("EVP_CIPHER_CTX_cleanup failed"); - } -#endif - - ldout(cct, 15) << __func__ - << " payload.length()=" << payload.length() - << " out_tmp->length()=" << out_tmp->length() - << " update_len=" << update_len - << " final_len=" << final_len - << dendl; - ceph_assert(update_len + final_len + STREAM_GCM_TAG_LEN == out_tmp->length()); - - payload.clear(); - payload.push_back(std::move(out_tmp)); - nonce++; -} - -void AES128GCM_StreamHandler::authenticated_decrypt( - char* payload, - uint32_t& length) -{ - ceph_assert(length > 0); - ceph_assert(length % AES_BLOCK_LEN == 0); - if (1 != EVP_DecryptInit_ex(ectx.get(), EVP_aes_128_gcm(), - nullptr, nullptr, nullptr)) { - throw std::runtime_error("EVP_DecryptInit_ex failed"); - } - - if (1 != EVP_CIPHER_CTX_ctrl(ectx.get(), EVP_CTRL_GCM_SET_IVLEN, - STREAM_AES_IV_LEN, nullptr) ) { - throw std::runtime_error("EVP_CIPHER_CTX_ctrl failed"); - } - - if(1 != EVP_DecryptInit_ex(ectx.get(), nullptr, nullptr, - reinterpret_cast(connection_secret.data()), - reinterpret_cast(&nonce))) { - throw std::runtime_error("EVP_DecryptInit_ex failed"); - } - - // TODO: consider in-place transformata - auto out_tmp = \ - ceph::buffer::ptr_node::create(length - STREAM_GCM_TAG_LEN); - - int update_len = 0; - if (1 != EVP_DecryptUpdate(ectx.get(), - reinterpret_cast(out_tmp->c_str()), - &update_len, - reinterpret_cast(payload), - length - STREAM_GCM_TAG_LEN)) { - throw std::runtime_error("EVP_DecryptUpdate failed"); - } - - if (1 != EVP_CIPHER_CTX_ctrl(ectx.get(), EVP_CTRL_GCM_SET_TAG, - STREAM_GCM_TAG_LEN, - payload + length - STREAM_GCM_TAG_LEN)) { - throw std::runtime_error("EVP_CIPHER_CTX_ctrl failed"); - } - - int final_len = 0; - if (0 >= EVP_DecryptFinal_ex(ectx.get(), - reinterpret_cast(out_tmp->c_str() + update_len), - &final_len)) { - ldout(cct, 15) << __func__ - << " length=" << length - << " out_tmp->length()=" << out_tmp->length() - << " update_len=" << update_len - << " final_len=" << final_len - << dendl; - throw std::runtime_error("EVP_DecryptFinal_ex failed"); - } else { - ceph_assert_always(update_len + final_len + STREAM_GCM_TAG_LEN == length); - ceph_assert_always((update_len + final_len) % AES_BLOCK_LEN == 0); - - // BE CAREFUL: we cannot expose any single bit of information about - // the cause of failure. Otherwise we'll face padding oracle attack. - // See: https://en.wikipedia.org/wiki/Padding_oracle_attack. - const auto pad_len = \ - std::min((*out_tmp)[update_len + final_len - 1], AES_BLOCK_LEN); - - // TODO: move to a new interface after dropping AES-CBC-HMAC-SHA256 - length = update_len + final_len - pad_len; - memcpy(payload, out_tmp->c_str(), length); - nonce++; - } -} - - -AuthStreamHandler::rxtx_t AuthStreamHandler::create_stream_handler_pair( - CephContext* cct, - const class AuthConnectionMeta& auth_meta) -{ - if (auth_meta.is_mode_secure()) { - // CLEANME, CLEANME CLEANME - ceph_assert_always( - auth_meta.connection_secret.length() >= 16 + 2*sizeof(ceph::uint128_t)); - - ceph::uint128_t rx_nonce; - ::memcpy(&rx_nonce, auth_meta.connection_secret.c_str() + 16, sizeof(rx_nonce)); - - ceph::uint128_t tx_nonce; - ::memcpy(&tx_nonce, auth_meta.connection_secret.c_str() + 16 + sizeof(rx_nonce), - sizeof(tx_nonce)); - return { - std::make_unique(cct, auth_meta, rx_nonce), - std::make_unique(cct, auth_meta, tx_nonce) - }; - } else { - return { nullptr, nullptr }; - } -} diff --git a/src/auth/AuthSessionHandler.h b/src/auth/AuthSessionHandler.h index 2b0d952c411b..6e54f1cee00d 100644 --- a/src/auth/AuthSessionHandler.h +++ b/src/auth/AuthSessionHandler.h @@ -41,45 +41,8 @@ struct DummyAuthSessionHandler : AuthSessionHandler { } }; -struct SHA256SignatureError : public std::exception { - sha256_digest_t sig1; - sha256_digest_t sig2; - std::string reason; - - SHA256SignatureError(const char *sig1, const char *sig2) - : sig1((const unsigned char *)sig1), sig2((const unsigned char *)sig2) { - std::stringstream ss; - ss << " signature mismatch: calc signature=" << this->sig1 - << " msg signature=" << this->sig2; - reason = ss.str(); - } - - const char *what() const throw() { return reason.c_str(); } -}; - struct DecryptionError : public std::exception {}; -struct AuthStreamHandler { - virtual ~AuthStreamHandler() = default; - //virtual ceph::bufferlist authenticated_encrypt(ceph::bufferlist& in) = 0; - //virtual ceph::bufferlist authenticated_decrypt(ceph::bufferlist& in) = 0; - virtual void authenticated_encrypt(ceph::bufferlist& payload) = 0; - virtual void authenticated_decrypt(char* payload, uint32_t& length) = 0; - virtual std::size_t calculate_payload_size(std::size_t length) = 0; - - struct rxtx_t { - //rxtx_t(rxtx_t&& r) : rx(std::move(rx)), tx(std::move(tx)) {} - // Each peer can use different handlers. - // Hmm, isn't that too much flexbility? - std::unique_ptr rx; - std::unique_ptr tx; - }; - static rxtx_t create_stream_handler_pair( - CephContext* ctx, - const class AuthConnectionMeta& auth_meta); -}; - -// TODO: make this a static member of AuthSessionHandler. extern AuthSessionHandler *get_auth_session_handler( CephContext *cct, int protocol, const CryptoKey& key, diff --git a/src/msg/async/ProtocolV2.cc b/src/msg/async/ProtocolV2.cc index 3dac54b350c1..5a856d71c979 100644 --- a/src/msg/async/ProtocolV2.cc +++ b/src/msg/async/ProtocolV2.cc @@ -277,13 +277,6 @@ template struct SignedEncryptedFrame : public PayloadFrame { SignedEncryptedFrame(ProtocolV2 &protocol, const Args &... args) : PayloadFrame(args...) { -#if 0 - ceph::bufferlist trans_bl; - this->payload.splice(8, this->payload.length() - 8, &trans_bl); - protocol.authencrypt_payload(trans_bl); - this->payload.claim_append(trans_bl); - -#else ceph_assert(protocol.session_stream_handlers.tx); protocol.session_stream_handlers.tx->reset_tx_handler({ @@ -301,15 +294,10 @@ struct SignedEncryptedFrame : public PayloadFrame { std::move(this->payload)); this->payload = \ protocol.session_stream_handlers.tx->authenticated_encrypt_final(); -#endif } SignedEncryptedFrame(ProtocolV2 &protocol, char *payload, uint32_t length) : PayloadFrame() { -#if 0 - protocol.authdecrypt_payload(payload, length); - this->decode_frame(payload, length); -#else protocol.session_stream_handlers.rx->reset_rx_handler(); ceph::bufferlist bl; @@ -319,7 +307,6 @@ struct SignedEncryptedFrame : public PayloadFrame { protocol.session_stream_handlers.rx->authenticated_decrypt_update_final( std::move(bl), 8); this->decode_frame(plain_bl.c_str(), plain_bl.length()); -#endif } }; @@ -1121,40 +1108,6 @@ bool ProtocolV2::is_queued() { return !out_queue.empty() || connection->is_queued(); } -uint32_t ProtocolV2::calculate_payload_size( - AuthStreamHandler *stream_handler, - uint32_t length) -{ -#if 0 - if (auth_meta.is_mode_secure()) { - ceph_assert(stream_handler != nullptr); - return stream_handler->calculate_payload_size(length); - } else { - return length; - } -#else - return length; -#endif -} - -void ProtocolV2::authencrypt_payload(bufferlist &payload) { - if (auth_meta->is_mode_secure()) { - // using tx - ceph_assert(session_security.tx); - session_security.tx->authenticated_encrypt(payload); - ceph_assert(payload.length() > 0); - } -} - -void ProtocolV2::authdecrypt_payload(char *payload, uint32_t &length) { - if (auth_meta->is_mode_secure()) { - ceph_assert(session_security.rx); - // using rx - ceph_assert(length > 0); - session_security.rx->authenticated_decrypt(payload, length); - } -} - CtPtr ProtocolV2::read(CONTINUATION_PARAM(next, ProtocolV2, char *, int), int len, char *buffer) { if (!buffer) { @@ -2910,7 +2863,6 @@ CtPtr ProtocolV2::reuse_connection(AsyncConnectionRef existing, exproto->can_write = false; exproto->reconnecting = reconnecting; exproto->replacing = true; - std::swap(exproto->session_security, session_security); std::swap(exproto->session_stream_handlers, session_stream_handlers); exproto->auth_meta = auth_meta; existing->state_offset = 0; diff --git a/src/msg/async/ProtocolV2.h b/src/msg/async/ProtocolV2.h index 92f64fa7b60e..8589015d6124 100644 --- a/src/msg/async/ProtocolV2.h +++ b/src/msg/async/ProtocolV2.h @@ -78,7 +78,6 @@ private: char *temp_buffer; State state; uint64_t peer_required_features; - AuthStreamHandler::rxtx_t session_security; uint64_t client_cookie; uint64_t server_cookie; @@ -204,13 +203,6 @@ public: virtual void write_event() override; virtual bool is_queued() override; - uint32_t calculate_payload_size( - AuthStreamHandler *stream_handler, - uint32_t length); - // We are doing *authenticated encryption* - void authencrypt_payload(ceph::bufferlist &payload); - void authdecrypt_payload(char *payload, uint32_t &length); - private: // Client Protocol CONTINUATION_DECL(ProtocolV2, start_client_banner_exchange);