From b602333f3995563f5cfdeccdca25eaa248bea770 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Thu, 27 Feb 2025 16:14:06 -0500 Subject: [PATCH] auth/cephx: modify client + server challenges hashing This applies when using ciphers that are not the original AES-128 one. Use the hmac-sha256 hash now. With AES256KRB5 the original method of encrypting the combined challenges doesn't work as the confounder randomizes the result. Signed-off-by: Yehuda Sadeh --- src/auth/Crypto.cc | 5 ++++- src/auth/Crypto.h | 2 +- src/auth/cephx/CephxProtocol.cc | 17 +++++++++++++++-- src/auth/cephx/CephxProtocol.h | 13 +++++++++++++ 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/auth/Crypto.cc b/src/auth/Crypto.cc index aedf1a2ed4a..b05473442fe 100644 --- a/src/auth/Crypto.cc +++ b/src/auth/Crypto.cc @@ -315,6 +315,7 @@ public: int encrypt(CephContext *cct, const ceph::bufferlist& in, ceph::bufferlist& out, std::string* /* unused */) const override { + ldout(cct, 20) << "CryptoAESKeyHandler::encrypt()" << dendl; // 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. @@ -357,6 +358,7 @@ public: int decrypt(CephContext *cct, const ceph::bufferlist& in, ceph::bufferlist& out, std::string* /* unused */) const override { + ldout(cct, 20) << "CryptoAESKeyHandler::decrypt()" << dendl; // PKCS#7 padding enlarges even empty plain-text to take 16 bytes. if (in.length() < AES_BLOCK_LEN || in.length() % AES_BLOCK_LEN) { return -1; @@ -746,6 +748,7 @@ public: int encrypt(CephContext *cct, const ceph::bufferlist& in, ceph::bufferlist& out, std::string* /* unused */) const override { + ldout(cct, 20) << "CryptoAES256KRB5KeyHandler::encrypt()" << dendl; // encrypted (confounder | data) | hash ceph::bufferptr out_tmp{static_cast( AES256KRB5_BLOCK_LEN + in.length() + AES256KRB5_HASH_LEN)}; @@ -795,6 +798,7 @@ public: ceph::bufferlist& out, std::string* /* unused */) const override { + ldout(cct, 20) << "CryptoAES256KRB5KeyHandler::decrypt()" << dendl; if (in.length() < AES256KRB5_BLOCK_LEN + AES256KRB5_HASH_LEN) { /* minimum size: confounder + hmac */ return -EINVAL; } @@ -862,7 +866,6 @@ public: return 0; } - }; diff --git a/src/auth/Crypto.h b/src/auth/Crypto.h index 9281b37c799..c72fbdb1318 100644 --- a/src/auth/Crypto.h +++ b/src/auth/Crypto.h @@ -188,7 +188,7 @@ public: return ckh->encrypt(cct, in, out); } - sha256_digest_t hmac_sha256(CephContext*, const ceph::buffer::list& in) { + sha256_digest_t hmac_sha256(CephContext*, const ceph::buffer::list& in) const { ceph_assert(ckh); return ckh->hmac_sha256(in); } diff --git a/src/auth/cephx/CephxProtocol.cc b/src/auth/cephx/CephxProtocol.cc index ed7c1eb4dd9..797ff4dadcd 100644 --- a/src/auth/cephx/CephxProtocol.cc +++ b/src/auth/cephx/CephxProtocol.cc @@ -40,8 +40,21 @@ void cephx_calc_client_server_challenge(CephContext *cct, CryptoKey& secret, uin b.client_challenge = client_challenge; bufferlist enc; - if (encode_encrypt(cct, b, secret, enc, error)) - return; + switch (secret.get_type()) { + case CEPH_CRYPTO_AES: + if (encode_encrypt(cct, b, secret, enc, error)) + return; + break; + default: + /* + * AES256KRB5 has a builtin confounder that randomizes the result, + * so just encode_encrypt() cannot be used. We should use + * a cryptographic has anyway, keeping the old behavior + * for AES for backward compatibility. + */ + if (encode_hash(cct, b, secret, enc, error)) + return; + }; uint64_t k = 0; const ceph_le64 *p = (const ceph_le64 *)enc.c_str(); diff --git a/src/auth/cephx/CephxProtocol.h b/src/auth/cephx/CephxProtocol.h index f79558d7aca..914ed3aa336 100644 --- a/src/auth/cephx/CephxProtocol.h +++ b/src/auth/cephx/CephxProtocol.h @@ -673,4 +673,17 @@ int encode_encrypt(CephContext *cct, const T& t, const CryptoKey& key, return 0; } +template +int encode_hash(CephContext *cct, const T& t, const CryptoKey& key, + ceph::buffer::list& out, std::string &error) +{ + using ceph::encode; + ceph::buffer::list bl_enc; + /* simple encoding, we don't need to add any magic because this will not be decoded */ + ::encode(t, bl_enc); + sha256_digest_t hash = key.hmac_sha256(cct, bl_enc); + out.append((const char *)&hash, sizeof(hash)); + return 0; +} + #endif -- 2.47.3