diff --git a/src/msg/async/crypto_onwire.cc b/src/msg/async/crypto_onwire.cc index e04b63800ca04..0cd272eae4cd3 100644 --- a/src/msg/async/crypto_onwire.cc +++ b/src/msg/async/crypto_onwire.cc @@ -1,6 +1,7 @@ // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab +#include #include #include "crypto_onwire.h" @@ -10,33 +11,41 @@ #define dout_subsys ceph_subsys_ms +namespace ceph::crypto::onwire { + +static constexpr const std::size_t AESGCM_KEY_LEN{16}; +static constexpr const std::size_t AESGCM_IV_LEN{12}; +static constexpr const std::size_t AESGCM_TAG_LEN{16}; +static constexpr const std::size_t AESGCM_BLOCK_LEN{16}; + +struct nonce_t { + std::uint32_t random_seq; + std::uint64_t random_rest; +} __attribute__((packed)); +static_assert(sizeof(nonce_t) == AESGCM_IV_LEN); + +using key_t = std::array; + // 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 // https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf class AES128GCM_OnWireTxHandler : public ceph::crypto::onwire::TxHandler { - static constexpr const std::size_t AESGCM_KEY_LEN{16}; - static constexpr const std::size_t AESGCM_IV_LEN{12}; - static constexpr const std::size_t AESGCM_TAG_LEN{16}; - static constexpr const std::size_t AESGCM_BLOCK_LEN{16}; - - using nonce_t = std::array; - CephContext* const cct; std::unique_ptr ectx; ceph::bufferlist buffer; - // using GCC's "Tetra Integer" mode here - ceph::uint128_t nonce; + nonce_t nonce; + static_assert(sizeof(nonce) == AESGCM_IV_LEN); public: AES128GCM_OnWireTxHandler(CephContext* const cct, - const AuthConnectionMeta& auth_meta, - const ceph::uint128_t& nonce) + const key_t& key, + const nonce_t& nonce) : cct(cct), ectx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free), nonce(nonce) { - ceph_assert_always(auth_meta.connection_secret.length() >= AESGCM_KEY_LEN); ceph_assert_always(ectx); + ceph_assert_always(key.size() * CHAR_BIT == 128); if (1 != EVP_EncryptInit_ex(ectx.get(), EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) { @@ -44,9 +53,7 @@ class AES128GCM_OnWireTxHandler : public ceph::crypto::onwire::TxHandler { } if(1 != EVP_EncryptInit_ex(ectx.get(), nullptr, nullptr, - reinterpret_cast(auth_meta.connection_secret.c_str()), - nullptr)) { - //reinterpret_cast(&nonce))) { + key.data(), nullptr)) { throw std::runtime_error("EVP_EncryptInit_ex failed"); } } @@ -78,8 +85,7 @@ void AES128GCM_OnWireTxHandler::reset_tx_handler( buffer.reserve(std::accumulate(std::begin(update_size_sequence), std::end(update_size_sequence), AESGCM_TAG_LEN)); - // transplantate the nonce update management from OpenVPN's AES-GCM - nonce += 1ULL << 32; + ++nonce.random_seq; } void AES128GCM_OnWireTxHandler::authenticated_encrypt_update( @@ -133,31 +139,23 @@ ceph::bufferlist AES128GCM_OnWireTxHandler::authenticated_encrypt_final() return std::move(buffer); } - // RX PART class AES128GCM_OnWireRxHandler : public ceph::crypto::onwire::RxHandler { - static constexpr const std::size_t AESGCM_KEY_LEN{16}; - static constexpr const std::size_t AESGCM_IV_LEN{12}; - static constexpr const std::size_t AESGCM_TAG_LEN{16}; - static constexpr const std::size_t AESGCM_BLOCK_LEN{16}; - - using nonce_t = std::array; - CephContext* const cct; std::unique_ptr ectx; - // using GCC's "Tetra Integer" mode here - ceph::uint128_t nonce; + nonce_t nonce; + static_assert(sizeof(nonce) == AESGCM_IV_LEN); public: AES128GCM_OnWireRxHandler(CephContext* const cct, - const AuthConnectionMeta& auth_meta, - const ceph::uint128_t& nonce) + const key_t& key, + const nonce_t& nonce) : cct(cct), ectx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free), nonce(nonce) { - ceph_assert_always(auth_meta.connection_secret.length() >= AESGCM_KEY_LEN); ceph_assert_always(ectx); + ceph_assert_always(key.size() * CHAR_BIT == 128); if (1 != EVP_DecryptInit_ex(ectx.get(), EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) { @@ -165,8 +163,7 @@ class AES128GCM_OnWireRxHandler : public ceph::crypto::onwire::RxHandler { } if(1 != EVP_DecryptInit_ex(ectx.get(), nullptr, nullptr, - reinterpret_cast(auth_meta.connection_secret.c_str()), - nullptr)) { + key.data(), nullptr)) { throw std::runtime_error("EVP_DecryptInit_ex failed"); } } @@ -193,7 +190,7 @@ void AES128GCM_OnWireRxHandler::reset_rx_handler() reinterpret_cast(&nonce))) { throw std::runtime_error("EVP_DecryptInit_ex failed"); } - nonce += 1ULL << 32; + ++nonce.random_seq; } ceph::bufferlist AES128GCM_OnWireRxHandler::authenticated_decrypt_update( @@ -288,23 +285,37 @@ ceph::crypto::onwire::rxtx_t ceph::crypto::onwire::rxtx_t::create_handler_pair( bool crossed) { if (auth_meta.is_mode_secure()) { - // CLEANME, CLEANME CLEANME - ceph_assert_always( - auth_meta.connection_secret.length() >= 16 + 2*sizeof(ceph::uint128_t)); + ceph_assert_always(auth_meta.connection_secret.length() >= \ + sizeof(key_t) + 2 * sizeof(nonce_t)); + const char* secbuf = auth_meta.connection_secret.c_str(); + + key_t key; + { + ::memcpy(key.data(), secbuf, sizeof(key)); + secbuf += sizeof(key); + } - ceph::uint128_t rx_nonce; - ::memcpy(&rx_nonce, auth_meta.connection_secret.c_str() + 16, sizeof(rx_nonce)); + nonce_t rx_nonce; + { + ::memcpy(&rx_nonce, secbuf, sizeof(rx_nonce)); + secbuf += sizeof(rx_nonce); + } + + nonce_t tx_nonce; + { + ::memcpy(&tx_nonce, secbuf, sizeof(tx_nonce)); + secbuf += sizeof(tx_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, crossed ? tx_nonce : rx_nonce), + cct, key, crossed ? tx_nonce : rx_nonce), std::make_unique( - cct, auth_meta, crossed ? rx_nonce : tx_nonce) + cct, key, crossed ? rx_nonce : tx_nonce) }; } else { return { nullptr, nullptr }; } } + +} // namespace ceph::crypto::onwire