From: Marcus Watts Date: Mon, 22 Aug 2022 07:38:18 +0000 (-0400) Subject: rgw: tempurl signature fixes: support sha256 and sha512 X-Git-Tag: v18.2.5~335^2~1 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=1906af7dcc8beb8535c0e413b7ab805739d57fd5;p=ceph.git rgw: tempurl signature fixes: support sha256 and sha512 The latest openstack swift logic supports sha256 and sha512 checksums for tempurl and formpost, which can be either hexadecimal or hashname:base64. This adds logic to inspect the incoming signature for type and to internally construct the same hash to compare. Also:: fixes an incidental crash if a malformed swift path does not contain an object name. Fixes: https://tracker.ceph.com/issues/56564 Signed-off-by: Marcus Watts (cherry picked from commit e2023d28dc6e6e835303716e7235df720d33a01c) --- diff --git a/src/rgw/rgw_swift_auth.cc b/src/rgw/rgw_swift_auth.cc index 05d4b28c124ee..24bbaff6dbac4 100644 --- a/src/rgw/rgw_swift_auth.cc +++ b/src/rgw/rgw_swift_auth.cc @@ -82,7 +82,7 @@ void TempURLEngine::get_owner_info(const DoutPrefixProvider* dpp, const req_stat const string& bucket_name = s->init_state.url_bucket; /* TempURL requires that bucket and object names are specified. */ - if (bucket_name.empty() || s->object->empty()) { + if (bucket_name.empty() || rgw::sal::Object::empty(s->object)) { throw -EPERM; } @@ -190,66 +190,108 @@ std::string extract_swift_subuser(const std::string& swift_user_name) } } -class TempURLEngine::SignatureHelper -{ -private: - static constexpr uint32_t output_size = - CEPH_CRYPTO_HMACSHA1_DIGESTSIZE * 2 + 1; - - unsigned char dest[CEPH_CRYPTO_HMACSHA1_DIGESTSIZE]; // 20 - char dest_str[output_size]; - +template +class TempURLSignatureT : public rgw::auth::swift::FormatSignature { + using UCHARPTR = const unsigned char*; + using base_t = SignatureHelperT; + using format_signature_t = rgw::auth::swift::FormatSignature; public: - SignatureHelper() = default; - const char* calc(const std::string& key, const std::string_view& method, const std::string_view& path, const std::string& expires) { + HASHFLAVOR hmac((UCHARPTR) key.data(), key.size()); - using ceph::crypto::HMACSHA1; - using UCHARPTR = const unsigned char*; - - HMACSHA1 hmac((UCHARPTR) key.c_str(), key.size()); hmac.Update((UCHARPTR) method.data(), method.size()); hmac.Update((UCHARPTR) "\n", 1); hmac.Update((UCHARPTR) expires.c_str(), expires.size()); hmac.Update((UCHARPTR) "\n", 1); hmac.Update((UCHARPTR) path.data(), path.size()); - hmac.Final(dest); + hmac.Final(base_t::dest); - buf_to_hex((UCHARPTR) dest, sizeof(dest), dest_str); - - return dest_str; + return format_signature_t::result(); } - - bool is_equal_to(const std::string& rhs) const { - /* never allow out-of-range exception */ - if (rhs.size() < (output_size - 1)) { - return false; +}; /* TempURLSignatureT */ +class TempURLEngine::SignatureHelper { +public: + SignatureHelper() {}; + virtual ~SignatureHelper() {}; + virtual const char* calc(const std::string& key, + const std::string_view& method, + const std::string_view& path, + const std::string& expires) { + return nullptr; + } + virtual bool is_equal_to(const std::string& rhs) { + return false; + }; + static std::unique_ptr get_sig_helper(std::string_view x); +}; +class TempURLSignature { + friend TempURLEngine; + using BadSignatureHelper = TempURLEngine::SignatureHelper; + template + class SignatureHelper_x : public TempURLEngine::SignatureHelper + { + friend TempURLEngine; + TempURLSignatureT d; + public: + SignatureHelper_x() {}; + ~SignatureHelper_x() { }; + virtual const char* calc(const std::string& key, + const std::string_view& method, + const std::string_view& path, + const std::string& expires) { + return d.calc(key,method,path,expires); } - return rhs.compare(0 /* pos */, output_size, dest_str) == 0; + virtual bool is_equal_to(const std::string& rhs) { + return d.is_equal_to(rhs); + }; + }; +}; + +std::unique_ptr TempURLEngine::SignatureHelper::get_sig_helper(std::string_view x) { + size_t pos = x.find(':'); + if (pos == x.npos || pos <= 0) { + switch(x.length()) { + case CEPH_CRYPTO_HMACSHA1_DIGESTSIZE*2: + return std::make_unique>(); + case CEPH_CRYPTO_HMACSHA256_DIGESTSIZE*2: + return std::make_unique>(); + case CEPH_CRYPTO_HMACSHA512_DIGESTSIZE*2: + return std::make_unique>(); + } + return std::make_unique(); } + std::string_view type { x.substr(0,pos) }; + if (type == "sha1") { + return std::make_unique>(); + } else if (type == "sha256") { + return std::make_unique>(); + } else if (type == "sha512") { + return std::make_unique>(); + } + return std::make_unique(); +}; -}; /* TempURLEngine::SignatureHelper */ - -class TempURLEngine::PrefixableSignatureHelper - : private TempURLEngine::SignatureHelper { - using base_t = SignatureHelper; +class TempURLEngine::PrefixableSignatureHelper { const std::string_view decoded_uri; const std::string_view object_name; std::string_view no_obj_uri; const boost::optional prefix; + std::unique_ptr base_sig_helper; public: - PrefixableSignatureHelper(const std::string& _decoded_uri, + PrefixableSignatureHelper(const std::string_view sig, + const std::string& _decoded_uri, const std::string& object_name, const boost::optional prefix) : decoded_uri(_decoded_uri), object_name(object_name), - prefix(prefix) { + prefix(prefix), + base_sig_helper(TempURLEngine::SignatureHelper::get_sig_helper(sig)) { /* Transform: v1/acct/cont/obj - > v1/acct/cont/ * * NOTE(rzarzynski): we really want to substr() on std::string_view, @@ -257,23 +299,23 @@ public: * a temporary. */ no_obj_uri = \ decoded_uri.substr(0, decoded_uri.length() - object_name.length()); - } + }; const char* calc(const std::string& key, const std::string_view& method, const std::string_view& path, const std::string& expires) { if (!prefix) { - return base_t::calc(key, method, path, expires); + return base_sig_helper->calc(key, method, path, expires); } else { const auto prefixed_path = \ string_cat_reserve("prefix:", no_obj_uri, *prefix); - return base_t::calc(key, method, prefixed_path, expires); + return base_sig_helper->calc(key, method, prefixed_path, expires); } } bool is_equal_to(const std::string& rhs) const { - bool is_auth_ok = base_t::is_equal_to(rhs); + bool is_auth_ok = base_sig_helper->is_equal_to(rhs); if (prefix && is_auth_ok) { const auto prefix_uri = string_cat_reserve(no_obj_uri, *prefix); @@ -360,6 +402,7 @@ TempURLEngine::authenticate(const DoutPrefixProvider* dpp, const req_state* cons /* Need to try each combination of keys, allowed path and methods. */ PrefixableSignatureHelper sig_helper { + temp_url_sig, s->decoded_uri, s->object->get_name(), temp_url_prefix @@ -772,4 +815,3 @@ RGWOp *RGWHandler_SWIFT_Auth::op_get() { return new RGW_SWIFT_Auth_Get; } - diff --git a/src/rgw/rgw_swift_auth.h b/src/rgw/rgw_swift_auth.h index 85a103dbfd5aa..3564a6b39b5c6 100644 --- a/src/rgw/rgw_swift_auth.h +++ b/src/rgw/rgw_swift_auth.h @@ -11,6 +11,7 @@ #include "rgw_auth_keystone.h" #include "rgw_auth_filters.h" #include "rgw_sal.h" +#include "rgw_b64.h" #define RGW_SWIFT_TOKEN_EXPIRATION (15 * 60) @@ -39,6 +40,7 @@ public: /* TempURL: engine */ class TempURLEngine : public rgw::auth::Engine { + friend class TempURLSignature; using result_t = rgw::auth::Engine::result_t; CephContext* const cct; @@ -303,6 +305,120 @@ public: } }; +// shared logic for swift tempurl and formpost signatures +template +inline constexpr uint32_t signature_hash_size = -1; +template <> +inline constexpr uint32_t signature_hash_size = CEPH_CRYPTO_HMACSHA1_DIGESTSIZE; +template<> +inline constexpr uint32_t signature_hash_size = CEPH_CRYPTO_HMACSHA256_DIGESTSIZE; +template<> +inline constexpr uint32_t signature_hash_size = CEPH_CRYPTO_HMACSHA512_DIGESTSIZE; + +const char sha1_name[] = "sha1"; +const char sha256_name[] = "sha256"; +const char sha512_name[] = "sha512"; + +template +const char * signature_hash_name; +template<> +inline constexpr const char * signature_hash_name = sha1_name;; +template<> +inline constexpr const char * signature_hash_name = sha256_name; +template<> +inline constexpr const char * signature_hash_name = sha512_name; + +template +inline const uint32_t signature_hash_name_size = -1; +template<> +inline constexpr uint32_t signature_hash_name_size = sizeof sha1_name;; +template<> +inline constexpr uint32_t signature_hash_name_size = sizeof sha256_name; +template<> +inline constexpr uint32_t signature_hash_name_size = sizeof sha512_name; + +template +class SignatureHelperT { +protected: + static constexpr uint32_t hash_size = signature_hash_size; + static constexpr uint32_t output_size = hash_size * 2 + 1; + const char * signature_name = signature_hash_name; + uint32_t signature_name_size = signature_hash_name_size; + char dest_str[output_size]; + uint32_t dest_size = 0; + unsigned char dest[hash_size]; + +public: + ~SignatureHelperT() { }; + + void Update(const unsigned char *input, size_t length); + + const char* get_signature() const { + return dest_str; + } + + bool is_equal_to(const std::string& rhs) const { + /* never allow out-of-range exception */ + if (!dest_size || rhs.size() < dest_size) { + return false; + } + return rhs.compare(0 /* pos */, dest_size + 1, dest_str) == 0; + } +}; + +enum class SignatureFlavor { + BARE_HEX, + NAMED_BASE64 +}; + +template +class FormatSignature { +}; + +// hexadecimal +template +class FormatSignature : public SignatureHelperT { + using UCHARPTR = const unsigned char*; + using base_t = SignatureHelperT; +public: + const char *result() { + buf_to_hex((UCHARPTR) base_t::dest, + signature_hash_size, + base_t::dest_str); + base_t::dest_size = strlen(base_t::dest_str); + return base_t::dest_str; + }; +}; + +// prefix:base64 +template +class FormatSignature : public SignatureHelperT { + using UCHARPTR = const unsigned char*; + using base_t = SignatureHelperT; +public: + char * const result() { + const char *prefix = base_t::signature_name; + const int prefix_size = base_t::signature_name_size; + std::string_view dest_view((char*)base_t::dest, sizeof base_t::dest); + auto b { rgw::to_base64(dest_view) }; + for (auto &v: b ) { // translate to "url safe" (rfc 4648 section 5) + switch(v) { + case '+': v = '-'; break; + case '/': v = '_'; break; + } + } + base_t::dest_size = prefix_size + b.length(); + if (base_t::dest_size < base_t::output_size) { + ::memcpy(base_t::dest_str, prefix, prefix_size - 1); + base_t::dest_str[prefix_size-1] = ':'; + ::strcpy(base_t::dest_str + prefix_size, b.c_str()); + } else { + base_t::dest_size = 0; + } + return base_t::dest_str; + }; +}; + } /* namespace swift */ } /* namespace auth */ } /* namespace rgw */