Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rgw: swift: tempurl fixes for ceph #47723

Merged
merged 4 commits into from Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/common/ceph_crypto.h
Expand Up @@ -14,6 +14,7 @@
#define CEPH_CRYPTO_SHA1_DIGESTSIZE 20
#define CEPH_CRYPTO_HMACSHA256_DIGESTSIZE 32
#define CEPH_CRYPTO_SHA256_DIGESTSIZE 32
#define CEPH_CRYPTO_HMACSHA512_DIGESTSIZE 64
#define CEPH_CRYPTO_SHA512_DIGESTSIZE 64

#include <openssl/evp.h>
Expand Down Expand Up @@ -187,6 +188,12 @@ namespace TOPNSPC::crypto {
: HMAC(EVP_sha256(), key, length) {
}
};

struct HMACSHA512 : public HMAC {
HMACSHA512 (const unsigned char *key, size_t length)
: HMAC(EVP_sha512(), key, length) {
}
};
}


Expand All @@ -197,6 +204,7 @@ namespace TOPNSPC::crypto {

using ssl::HMACSHA256;
using ssl::HMACSHA1;
using ssl::HMACSHA512;

template<class Digest>
auto digest(const ceph::buffer::list& bl)
Expand Down
121 changes: 114 additions & 7 deletions src/rgw/rgw_rest_swift.cc
Expand Up @@ -42,6 +42,109 @@

using namespace std;

template <class HASHFLAVOR, rgw::auth::swift::SignatureFlavor SIGNATUREFLAVOR>
class FormPostSignatureT: public rgw::auth::swift::FormatSignature<HASHFLAVOR,SIGNATUREFLAVOR>
{
using UCHARPTR = const unsigned char*;
using base_t = rgw::auth::swift::SignatureHelperT<HASHFLAVOR>;
using format_signature_t = rgw::auth::swift::FormatSignature<HASHFLAVOR,SIGNATUREFLAVOR>;
public:
const char* calc(const std::string& key,
const std::string_view& path_info,
const std::string_view& redirect,
const std::string_view& max_file_size,
const std::string_view& max_file_count,
const std::string_view& expires) {
HASHFLAVOR hmac((UCHARPTR) key.data(), key.size());

hmac.Update((UCHARPTR) path_info.data(), path_info.size());
hmac.Update((UCHARPTR) "\n", 1);

hmac.Update((UCHARPTR) redirect.data(), redirect.size());
hmac.Update((UCHARPTR) "\n", 1);

hmac.Update((UCHARPTR) max_file_size.data(), max_file_size.size());
hmac.Update((UCHARPTR) "\n", 1);

hmac.Update((UCHARPTR) max_file_count.data(), max_file_count.size());
hmac.Update((UCHARPTR) "\n", 1);

hmac.Update((UCHARPTR) expires.data(), expires.size());

hmac.Final(base_t::dest);

return format_signature_t::result();
}
};
class RGWFormPost::SignatureHelper {
public:
virtual ~SignatureHelper() {};
virtual const char* calc(const std::string& key,
const std::string_view& path_info,
const std::string_view& redirect,
const std::string_view& max_file_size,
const std::string_view& max_file_count,
const std::string_view& expires) {
return nullptr;
};
virtual const char* get_signature() const {
return nullptr;
};
virtual bool is_equal_to(const std::string& rhs) {
return false;
};
static std::unique_ptr<SignatureHelper> get_sig_helper(std::string_view x);
};
template<typename HASHFLAVOR, rgw::auth::swift::SignatureFlavor SIGNATUREFLAVOR>
class RGWFormPost::SignatureHelper_x : public RGWFormPost::SignatureHelper
{
friend RGWFormPost;
private:
FormPostSignatureT<HASHFLAVOR,SIGNATUREFLAVOR> d;
public:
~SignatureHelper_x() { };
SignatureHelper_x() {};
virtual const char* calc(const std::string& key,
const std::string_view& path_info,
const std::string_view& redirect,
const std::string_view& max_file_size,
const std::string_view& max_file_count,
const std::string_view& expires) {
return d.calc(key,path_info,redirect,
max_file_size,max_file_count,expires) ;
};
virtual const char* get_signature() const {
return d.get_signature();
};
virtual bool is_equal_to(const std::string& rhs) {
return d.is_equal_to(rhs);
};
};

std::unique_ptr<RGWFormPost::SignatureHelper> RGWFormPost::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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why hasn't the template split removed the need for the switch statement? i.e., you've templated out the HMAC and (um, O) parameters in descendant template types. Could the ancestor types become abstract, maybe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The switch statement here is part of the logic that decides at run-time which of the 6 different forms of template logic it should realize. All the template logic happens strictly at compile-time, it can't replace the ultimate need to do grody old-fashioned run-time string parsing, which is what's happening here.
There are however 2 things I didn't do in this direction: firrstly, there are 2 copies of get_sig_helper, one for tempurl and one for formpost. It could be trivially one templated function, or less trivially, integrated into some other base class. There's no runtime advantage to this, and it makes include files a bit more messy.
The other thing is the template classes RGWFormPost::SignatureHelper_x and TempURLSignature::SignatureHelper_x, these both mainly contain thunks for calc() and is_equal_to(). Slightly more clever class logic might eliminate the need for those, but I kept ending up with worse kludges chasing that down.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the use of templates, sorry I seemed to be over reading here; I would rather we'd landed this in 22, rather than risking it getting stuck

return std::make_unique<SignatureHelper_x<ceph::crypto::HMACSHA1,rgw::auth::swift::SignatureFlavor::BARE_HEX>>();
case CEPH_CRYPTO_HMACSHA256_DIGESTSIZE*2:
return std::make_unique<SignatureHelper_x<ceph::crypto::HMACSHA256,rgw::auth::swift::SignatureFlavor::BARE_HEX>>();
case CEPH_CRYPTO_HMACSHA512_DIGESTSIZE*2:
return std::make_unique<SignatureHelper_x<ceph::crypto::HMACSHA512,rgw::auth::swift::SignatureFlavor::BARE_HEX>>();
}
return std::make_unique<BadSignatureHelper>();
}
std::string_view type { x.substr(0,pos) };
if (type == "sha1") {
return std::make_unique<SignatureHelper_x<ceph::crypto::HMACSHA1,rgw::auth::swift::SignatureFlavor::NAMED_BASE64>>();
} else if (type == "sha256") {
return std::make_unique<SignatureHelper_x<ceph::crypto::HMACSHA256,rgw::auth::swift::SignatureFlavor::NAMED_BASE64>>();
} else if (type == "sha512") {
return std::make_unique<SignatureHelper_x<ceph::crypto::HMACSHA512,rgw::auth::swift::SignatureFlavor::NAMED_BASE64>>();
}
return std::make_unique<BadSignatureHelper>();
};

int RGWListBuckets_ObjStore_SWIFT::get_params(optional_yield y)
{
prefix = s->info.args.get("prefix");
Expand Down Expand Up @@ -2034,6 +2137,7 @@ bool RGWFormPost::is_non_expired()
bool RGWFormPost::is_integral()
{
const std::string form_signature = get_part_str(ctrl_parts, "signature");
bool r = false;

try {
get_owner_info(s, s->user->get_info());
Expand All @@ -2051,28 +2155,31 @@ bool RGWFormPost::is_integral()
continue;
}

SignatureHelper sig_helper;
sig_helper.calc(temp_url_key,
auto sig_helper{ RGWFormPost::SignatureHelper::get_sig_helper(form_signature) };
sig_helper->calc(temp_url_key,
s->info.request_uri,
get_part_str(ctrl_parts, "redirect"),
get_part_str(ctrl_parts, "max_file_size", "0"),
get_part_str(ctrl_parts, "max_file_count", "0"),
get_part_str(ctrl_parts, "expires", "0"));

const auto local_sig = sig_helper.get_signature();
const char* local_sig = sig_helper->get_signature();
if (!local_sig) local_sig = "???";

ldpp_dout(this, 20) << "FormPost signature [" << temp_url_key_num << "]"
<< " (calculated): " << local_sig << dendl;

if (sig_helper.is_equal_to(form_signature)) {
return true;
} else {
r = sig_helper->is_equal_to(form_signature);
if (!r) {
ldpp_dout(this, 5) << "FormPost's signature mismatch: "
<< local_sig << " != " << form_signature << dendl;
}
if (r) {
break;
}
}

return false;
return r;
}

void RGWFormPost::get_owner_info(const req_state* const s,
Expand Down
60 changes: 2 additions & 58 deletions src/rgw/rgw_rest_swift.h
Expand Up @@ -263,6 +263,8 @@ class RGWFormPost : public RGWPostObj_ObjStore {
bool stream_done = false;

class SignatureHelper;
using BadSignatureHelper = SignatureHelper;
template<typename HASHFLAVOR, rgw::auth::swift::SignatureFlavor SIGNATUREFLAVOR> class SignatureHelper_x;
public:
RGWFormPost() = default;
~RGWFormPost() = default;
Expand All @@ -278,64 +280,6 @@ class RGWFormPost : public RGWPostObj_ObjStore {
static bool is_formpost_req(req_state* const s);
};

class RGWFormPost::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];

public:
SignatureHelper() = default;

const char* calc(const std::string& key,
const std::string_view& path_info,
const std::string_view& redirect,
const std::string_view& max_file_size,
const std::string_view& max_file_count,
const std::string_view& expires) {
using ceph::crypto::HMACSHA1;
using UCHARPTR = const unsigned char*;

HMACSHA1 hmac((UCHARPTR) key.data(), key.size());

hmac.Update((UCHARPTR) path_info.data(), path_info.size());
hmac.Update((UCHARPTR) "\n", 1);

hmac.Update((UCHARPTR) redirect.data(), redirect.size());
hmac.Update((UCHARPTR) "\n", 1);

hmac.Update((UCHARPTR) max_file_size.data(), max_file_size.size());
hmac.Update((UCHARPTR) "\n", 1);

hmac.Update((UCHARPTR) max_file_count.data(), max_file_count.size());
hmac.Update((UCHARPTR) "\n", 1);

hmac.Update((UCHARPTR) expires.data(), expires.size());

hmac.Final(dest);

buf_to_hex((UCHARPTR) dest, sizeof(dest), dest_str);

return dest_str;
}

const char* get_signature() const {
return dest_str;
}

bool is_equal_to(const std::string& rhs) const {
/* never allow out-of-range exception */
if (rhs.size() < (output_size - 1)) {
return false;
}
return rhs.compare(0 /* pos */, output_size, dest_str) == 0;
}

}; /* RGWFormPost::SignatureHelper */


class RGWSwiftWebsiteHandler {
rgw::sal::Driver* const driver;
Expand Down