From: Radoslaw Zarzynski Date: Wed, 23 Jan 2019 01:28:04 +0000 (+0100) Subject: msg/async: move crypto handling from ProtocolV2 into AuthStreamHandler. X-Git-Tag: v14.1.1~157^2~58 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=4d041a19a29e9dba7238acd915738cfe051ac7bb;p=ceph-ci.git msg/async: move crypto handling from ProtocolV2 into AuthStreamHandler. Signed-off-by: Radoslaw Zarzynski --- diff --git a/src/auth/Auth.h b/src/auth/Auth.h index 59370e25dc7..84cd5b3d01d 100644 --- a/src/auth/Auth.h +++ b/src/auth/Auth.h @@ -170,10 +170,10 @@ struct AuthConnectionMeta { int con_mode = 0; ///< negotiated mode - bool is_mode_crc() { + bool is_mode_crc() const { return con_mode == CEPH_CON_MODE_CRC; } - bool is_mode_secure() { + bool is_mode_secure() const { return con_mode == CEPH_CON_MODE_SECURE; } diff --git a/src/auth/AuthSessionHandler.cc b/src/auth/AuthSessionHandler.cc index 528b4ac698a..28e466898c6 100644 --- a/src/auth/AuthSessionHandler.cc +++ b/src/auth/AuthSessionHandler.cc @@ -21,6 +21,7 @@ #include "none/AuthNoneSessionHandler.h" #include "unknown/AuthUnknownSessionHandler.h" +#include "common/ceph_crypto.h" #define dout_subsys ceph_subsys_auth @@ -54,9 +55,197 @@ AuthSessionHandler *get_auth_session_handler( } } -std::unique_ptr AuthStreamHandler::create_stream_handler( - CephContext* ctx, - const class AuthConnectionMeta& auth_meta) +class AES128CBC_HMACSHA256_StreamHandler : public AuthStreamHandler { + CephContext* const cct; + const AuthConnectionMeta& auth_meta; + CryptoKey key; + + void calc_signature(const char *in, uint32_t length, char *out) { + auto secret = auth_meta.connection_secret; + ceph::crypto::HMACSHA256 hmac((const unsigned char *)secret.c_str(), + secret.length()); + hmac.Update((const unsigned char *)in, length); + hmac.Final((unsigned char *)out); + } + + void calculate_payload_size(uint32_t length, uint32_t *total_len, + uint32_t *sig_pad_len = nullptr, + uint32_t *enc_pad_len = nullptr) { + bool is_signed = auth_meta.is_mode_secure(); // REMOVE ME + bool is_encrypted = auth_meta.is_mode_secure(); + + uint32_t sig_pad_l = 0; + uint32_t enc_pad_l = 0; + uint32_t total_l = length; + + if (is_signed && !is_encrypted) { + sig_pad_l = SIGNATURE_BLOCK_SIZE - (length % SIGNATURE_BLOCK_SIZE); + total_l += sig_pad_l + SIGNATURE_BLOCK_SIZE; + } else if (is_encrypted) { + if (is_signed) { + total_l += SIGNATURE_BLOCK_SIZE; + } + uint32_t block_size = auth_meta.session_key.get_max_outbuf_size(0); + uint32_t pad_len = block_size - (total_l % block_size); + if (is_signed) { + sig_pad_l = pad_len; + } else if (!is_signed) { + enc_pad_l = pad_len; + } + total_l = auth_meta.session_key.get_max_outbuf_size(total_l + pad_len); + } + + if (sig_pad_len) { + *sig_pad_len = sig_pad_l; + } + if (enc_pad_len) { + *enc_pad_len = enc_pad_l; + } + if (total_len) { + *total_len = total_l; + } + + ldout(cct, 21) << __func__ << " length=" << length << " total_len=" << total_l + << " sig_pad_len=" << sig_pad_l << " enc_pad_len=" << enc_pad_l + << dendl; + } + + void sign_payload(bufferlist &payload) { + ldout(cct, 21) << __func__ << " len=" << payload.length() << dendl; + + if (false) { + uint32_t pad_len; + calculate_payload_size(payload.length(), nullptr, &pad_len); + auto padding = bufferptr(buffer::create(pad_len)); + cct->random()->get_bytes((char *)padding.raw_c_str(), pad_len); + payload.push_back(padding); + + auto signature = + bufferptr(buffer::create(CEPH_CRYPTO_HMACSHA256_DIGESTSIZE)); + calc_signature(payload.c_str(), payload.length(), + (char *)signature.raw_c_str()); + + uint64_t s1 = *(uint64_t *)signature.raw_c_str(); + uint64_t s2 = *(uint64_t *)(signature.raw_c_str() + 8); + uint64_t s3 = *(uint64_t *)(signature.raw_c_str() + 16); + uint64_t s4 = *(uint64_t *)(signature.raw_c_str() + 24); + ldout(cct, 15) << __func__ << " payload signature=" << std::hex << s4 << s3 + << s2 << s1 << std::dec << dendl; + + payload.push_back(signature); + } + } + + void verify_signature(char *payload, uint32_t length) { + ldout(cct, 21) << __func__ << " len=" << length << dendl; + + if (false) { + uint32_t payload_len = length - CEPH_CRYPTO_HMACSHA256_DIGESTSIZE; + const char *p = payload + payload_len; + char signature[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE]; + calc_signature(payload, payload_len, signature); + + auto r = memcmp(p, signature, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE); + + if (r != 0) { // signature mismatch + ldout(cct, 1) << __func__ << " signature verification failed" << dendl; + throw SHA256SignatureError(signature, p); + } + } + } + + int encrypt_bufferlist(bufferlist &in, bufferlist &out) { + std::string error; + try { + key.encrypt(cct, in, out, &error); + } catch (std::exception &e) { + lderr(cct) << __func__ << " failed to encrypt buffer: " << error << dendl; + return -1; + } + return 0; + } + + int decrypt_bufferlist(bufferlist &in, bufferlist &out) { + std::string error; + try { + key.decrypt(cct, in, out, &error); + } catch (std::exception &e) { + lderr(cct) << __func__ << " failed to decrypt buffer: " << error << dendl; + return -1; + } + return 0; + } + + void encrypt_payload(bufferlist &payload) { + ldout(cct, 21) << __func__ << " len=" << payload.length() << dendl; + if (auth_meta.is_mode_secure()) { + uint32_t pad_len; + calculate_payload_size(payload.length(), nullptr, nullptr, &pad_len); + if (pad_len) { + auto padding = bufferptr(buffer::create(pad_len)); + cct->random()->get_bytes((char *)padding.raw_c_str(), pad_len); + payload.push_back(padding); + } + + bufferlist tmp; + tmp.claim(payload); + encrypt_bufferlist(tmp, payload); + } + } + + void decrypt_payload(char *payload, uint32_t &length) { + ldout(cct, 21) << __func__ << " len=" << length << dendl; + if (auth_meta.is_mode_secure()) { + bufferlist in; + in.push_back(buffer::create_static(length, payload)); + bufferlist out; + if (decrypt_bufferlist(in, out) < 0) { + throw DecryptionError(); + } + ceph_assert(out.length() <= length); + memcpy(payload, out.c_str(), out.length()); + length = out.length(); + } + } + + /* HMAC Block Size + * Currently we're using only SHA256 for computing the HMAC + */ + static const int SIGNATURE_BLOCK_SIZE = CEPH_CRYPTO_HMACSHA256_DIGESTSIZE; + +public: + AES128CBC_HMACSHA256_StreamHandler(CephContext* const cct, + const AuthConnectionMeta& auth_meta) + : cct(cct), + auth_meta(auth_meta), +#warning fixme key + key(auth_meta.session_key) { + } + + void authenticated_encrypt(ceph::bufferlist& payload) override { + sign_payload(payload); + encrypt_payload(payload); + } + + void authenticated_decrypt(char* payload, uint32_t& length) override { + decrypt_payload(payload, length); + verify_signature(payload, length); + } + + std::size_t calculate_payload_size(std::size_t length) override { + uint32_t total_l; + calculate_payload_size(length, &total_l); + return total_l; + } +}; + + +AuthStreamHandler::rxtx_t AuthStreamHandler::create_stream_handler_pair( + CephContext* cct, + const class AuthConnectionMeta& auth_meta) { - return std::make_unique(); + return { + std::make_shared(cct, auth_meta), + std::make_shared(cct, auth_meta) + }; } diff --git a/src/auth/AuthSessionHandler.h b/src/auth/AuthSessionHandler.h index b291e9e067d..080f73c2d73 100644 --- a/src/auth/AuthSessionHandler.h +++ b/src/auth/AuthSessionHandler.h @@ -41,6 +41,24 @@ 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 {}; + // TODO: make this a static member of AuthSessionHandler. extern AuthSessionHandler *get_auth_session_handler( CephContext *cct, int protocol, @@ -52,16 +70,18 @@ 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; - // TODO: kill the dummies - int encrypt_bufferlist(bufferlist &in, bufferlist &out) { - return 0; - } - int decrypt_bufferlist(bufferlist &in, bufferlist &out) { - return 0; - } - - static std::unique_ptr create_stream_handler( + 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::shared_ptr rx; + std::shared_ptr tx; + }; + static rxtx_t create_stream_handler_pair( CephContext* ctx, const class AuthConnectionMeta& auth_meta); }; diff --git a/src/auth/cephx/CephxSessionHandler.cc b/src/auth/cephx/CephxSessionHandler.cc index bf5ffe1a48e..16c12518416 100644 --- a/src/auth/cephx/CephxSessionHandler.cc +++ b/src/auth/cephx/CephxSessionHandler.cc @@ -180,25 +180,3 @@ int CephxSessionHandler::check_message_signature(Message *m) return 0; } - -int CephxSessionHandler::encrypt_bufferlist(bufferlist &in, bufferlist &out) { - std::string error; - try { - key.encrypt(cct, in, out, &error); - } catch (std::exception &e) { - lderr(cct) << __func__ << " failed to encrypt buffer: " << error << dendl; - return -1; - } - return 0; -} - -int CephxSessionHandler::decrypt_bufferlist(bufferlist &in, bufferlist &out) { - std::string error; - try { - key.decrypt(cct, in, out, &error); - } catch (std::exception &e) { - lderr(cct) << __func__ << " failed to decrypt buffer: " << error << dendl; - return -1; - } - return 0; -} diff --git a/src/auth/cephx/CephxSessionHandler.h b/src/auth/cephx/CephxSessionHandler.h index 32a143a818b..6a6a99f1842 100644 --- a/src/auth/cephx/CephxSessionHandler.h +++ b/src/auth/cephx/CephxSessionHandler.h @@ -40,8 +40,5 @@ public: int sign_message(Message *m) override; int check_message_signature(Message *m) override ; - - int encrypt_bufferlist(bufferlist &in, bufferlist &out); - int decrypt_bufferlist(bufferlist &in, bufferlist &out); }; diff --git a/src/msg/async/ProtocolV2.cc b/src/msg/async/ProtocolV2.cc index 19e0169d2fb..03bd9e941be 100644 --- a/src/msg/async/ProtocolV2.cc +++ b/src/msg/async/ProtocolV2.cc @@ -42,23 +42,6 @@ const uint64_t msgr2_frame_assumed = using CtPtr = Ct *; -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 {}; void ProtocolV2::run_continuation(CtPtr continuation) { try { @@ -75,21 +58,8 @@ void ProtocolV2::run_continuation(CtPtr continuation) { } } -void ProtocolV2::calc_signature(const char *in, uint32_t length, char *out) { - auto secret = auth_meta.session_key.get_secret(); - ceph::crypto::HMACSHA256 hmac((const unsigned char *)secret.c_str(), - secret.length()); - hmac.Update((const unsigned char *)in, length); - hmac.Final((unsigned char *)out); -} - const int ASYNC_COALESCE_THRESHOLD = 256; -/* HMAC Block Size - * Currently we're using only SHA256 for computing the HMAC - */ -const int SIGNATURE_BLOCK_SIZE = CEPH_CRYPTO_HMACSHA256_DIGESTSIZE; - #define WRITE(B, D, C) write(D, CONTINUATION(C), B) #define READ(L, C) read(CONTINUATION(C), L) @@ -1093,132 +1063,29 @@ bool ProtocolV2::is_queued() { return !out_queue.empty() || connection->is_queued(); } -void ProtocolV2::sign_payload(bufferlist &payload) { - ldout(cct, 21) << __func__ << " len=" << payload.length() << dendl; - - if (false && session_security) { - uint32_t pad_len; - calculate_payload_size(payload.length(), nullptr, &pad_len); - auto padding = bufferptr(buffer::create(pad_len)); - cct->random()->get_bytes((char *)padding.raw_c_str(), pad_len); - payload.push_back(padding); - - auto signature = - bufferptr(buffer::create(CEPH_CRYPTO_HMACSHA256_DIGESTSIZE)); - calc_signature(payload.c_str(), payload.length(), - (char *)signature.raw_c_str()); - - uint64_t s1 = *(uint64_t *)signature.raw_c_str(); - uint64_t s2 = *(uint64_t *)(signature.raw_c_str() + 8); - uint64_t s3 = *(uint64_t *)(signature.raw_c_str() + 16); - uint64_t s4 = *(uint64_t *)(signature.raw_c_str() + 24); - ldout(cct, 15) << __func__ << " payload signature=" << std::hex << s4 << s3 - << s2 << s1 << std::dec << dendl; - - payload.push_back(signature); - } -} - -void ProtocolV2::verify_signature(char *payload, uint32_t length) { - ldout(cct, 21) << __func__ << " len=" << length << dendl; - - if (false && session_security) { - uint32_t payload_len = length - CEPH_CRYPTO_HMACSHA256_DIGESTSIZE; - const char *p = payload + payload_len; - char signature[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE]; - calc_signature(payload, payload_len, signature); - - auto r = memcmp(p, signature, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE); - - if (r != 0) { // signature mismatch - ldout(cct, 1) << __func__ << " signature verification failed" << dendl; - throw SHA256SignatureError(signature, p); - } - } -} - -void ProtocolV2::encrypt_payload(bufferlist &payload) { - ldout(cct, 21) << __func__ << " len=" << payload.length() << dendl; - if (auth_meta->is_mode_secure()) { - uint32_t pad_len; - calculate_payload_size(payload.length(), nullptr, nullptr, &pad_len); - if (pad_len) { - auto padding = bufferptr(buffer::create(pad_len)); - cct->random()->get_bytes((char *)padding.raw_c_str(), pad_len); - payload.push_back(padding); - } - - bufferlist tmp; - tmp.claim(payload); - session_security->encrypt_bufferlist(tmp, payload); - } -} - -void ProtocolV2::decrypt_payload(char *payload, uint32_t &length) { - ldout(cct, 21) << __func__ << " len=" << length << dendl; - if (auth_meta->is_mode_secure() && session_security) { - bufferlist in; - in.push_back(buffer::create_static(length, payload)); - bufferlist out; - if (session_security->decrypt_bufferlist(in, out) < 0) { - throw DecryptionError(); - } - ceph_assert(out.length() <= length); - memcpy(payload, out.c_str(), out.length()); - length = out.length(); - } -} - -void ProtocolV2::calculate_payload_size(uint32_t length, uint32_t *total_len, - uint32_t *sig_pad_len, - uint32_t *enc_pad_len) { - bool is_signed = auth_meta->is_mode_secure(); // REMOVE ME - bool is_encrypted = auth_meta->is_mode_secure(); - - uint32_t sig_pad_l = 0; - uint32_t enc_pad_l = 0; - uint32_t total_l = length; - - if (is_signed && !is_encrypted) { - sig_pad_l = SIGNATURE_BLOCK_SIZE - (length % SIGNATURE_BLOCK_SIZE); - total_l += sig_pad_l + SIGNATURE_BLOCK_SIZE; - } else if (is_encrypted) { - if (is_signed) { - total_l += SIGNATURE_BLOCK_SIZE; - } - uint32_t block_size = auth_meta.session_key.get_max_outbuf_size(0); - uint32_t pad_len = block_size - (total_l % block_size); - if (is_signed) { - sig_pad_l = pad_len; - } else if (!is_signed) { - enc_pad_l = pad_len; - } - total_l = auth_meta.session_key.get_max_outbuf_size(total_l + pad_len); - } - - if (sig_pad_len) { - *sig_pad_len = sig_pad_l; - } - if (enc_pad_len) { - *enc_pad_len = enc_pad_l; - } - if (total_len) { - *total_len = total_l; +uint32_t ProtocolV2::calculate_payload_size( + AuthStreamHandler *stream_handler, + uint32_t length) +{ + if (stream_handler) { + return stream_handler->calculate_payload_size(length); + } else { + return length; } - - ldout(cct, 21) << __func__ << " length=" << length << " total_len=" << total_l - << " sig_pad_len=" << sig_pad_l << " enc_pad_len=" << enc_pad_l - << dendl; } void ProtocolV2::authencrypt_payload(bufferlist &payload) { - sign_payload(payload); - encrypt_payload(payload); + // using tx + if (session_security.tx) { + session_security.tx->authenticated_encrypt(payload); + } } void ProtocolV2::authdecrypt_payload(char *payload, uint32_t &length) { - decrypt_payload(payload, length); - verify_signature(payload, length); + // using rx + if (session_security.rx) { + session_security.rx->authenticated_decrypt(payload, length); + } } CtPtr ProtocolV2::read(CONTINUATION_PARAM(next, ProtocolV2, char *, int), @@ -1602,8 +1469,8 @@ CtPtr ProtocolV2::handle_message() { #endif recv_stamp = ceph_clock_now(); - uint32_t header_len; - calculate_payload_size(sizeof(ceph_msg_header2), &header_len); + const uint32_t header_len = calculate_payload_size( + session_security.rx.get(), sizeof(ceph_msg_header2)); return READ(header_len, handle_message_header); } @@ -1615,8 +1482,8 @@ CtPtr ProtocolV2::handle_message_header(char *buffer, int r) { return _fault(); } - uint32_t header_len; - calculate_payload_size(sizeof(ceph_msg_header2), &header_len); + const uint32_t header_len = calculate_payload_size( + session_security.rx.get(), sizeof(ceph_msg_header2)); MessageHeaderFrame header_frame(this, buffer, header_len); ceph_msg_header2 &header = header_frame.header(); @@ -1853,7 +1720,8 @@ CtPtr ProtocolV2::read_message_data() { // the message payload ldout(cct, 1) << __func__ << " reading message payload extra bytes left=" << next_payload_len << dendl; - ceph_assert(session_security && (auth_meta->is_mode_secure())); + ceph_assert(session_security.rx && session_security.tx && + auth_meta->is_mode_secure()); extra.push_back(buffer::create(next_payload_len)); return READB(next_payload_len, extra.c_str(), handle_message_extra_bytes); } @@ -2244,8 +2112,8 @@ CtPtr ProtocolV2::handle_auth_done(char *payload, uint32_t length) { if (r < 0) { return _fault(); } - session_security.reset( - AuthStreamHandler::create_stream_handler(cct, auth_meta).release()); + session_security = + AuthStreamHandler::create_stream_handler_pair(cct, auth_meta); if (!server_cookie) { ceph_assert(connect_seq == 0); diff --git a/src/msg/async/ProtocolV2.h b/src/msg/async/ProtocolV2.h index 2bb7dc4dce7..d578d378bd8 100644 --- a/src/msg/async/ProtocolV2.h +++ b/src/msg/async/ProtocolV2.h @@ -75,7 +75,7 @@ private: char *temp_buffer; State state; uint64_t peer_required_features; - std::shared_ptr session_security; + AuthStreamHandler::rxtx_t session_security; uint64_t client_cookie; uint64_t server_cookie; @@ -110,7 +110,6 @@ private: ostream &_conn_prefix(std::ostream *_dout); void run_continuation(Ct *continuation); - void calc_signature(const char *in, uint32_t length, char *out); Ct *read(CONTINUATION_PARAM(next, ProtocolV2, char *, int), int len, char *buffer = nullptr); @@ -198,14 +197,9 @@ public: virtual void write_event() override; virtual bool is_queued() override; - void sign_payload(bufferlist &payload); - void verify_signature(char *payload, uint32_t length); - void encrypt_payload(bufferlist &payload); - void decrypt_payload(char *payload, uint32_t &length); - void calculate_payload_size(uint32_t length, uint32_t *total_len, - uint32_t *sig_pad_len = nullptr, - uint32_t *enc_pad_len = nullptr); - + 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);