From ec5c3b28d957725dfd1c4b14a92ba4beac12515b Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Thu, 21 Apr 2022 14:44:01 -0400 Subject: [PATCH] rgw: RGWPutLC does not require Content-MD5 amazon docs for PutBucketLifecycleConfiguration do say that a Content-MD5 header is required, but clients in FIPS mode may not be able to generate this header. MD5 should not be used as a security feature, so rgw shouldn't require it here. if no Content-MD5 is given, just skip the checksum verification instead of rejecting the request Fixes: https://tracker.ceph.com/issues/55339 Signed-off-by: Casey Bodley --- src/rgw/rgw_op.cc | 62 ++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 961d3aec8e0e2..7d52a80881218 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -5797,23 +5797,23 @@ void RGWPutLC::execute(optional_yield y) RGWXMLParser parser; RGWLifecycleConfiguration_S3 new_config(s->cct); - content_md5 = s->info.env->get("HTTP_CONTENT_MD5"); - if (content_md5 == nullptr) { - op_ret = -ERR_INVALID_REQUEST; - s->err.message = "Missing required header for this request: Content-MD5"; - ldpp_dout(this, 5) << s->err.message << dendl; - return; - } + // amazon says that Content-MD5 is required for this op specifically, but MD5 + // is not a security primitive and FIPS mode makes it difficult to use. if the + // client provides the header we'll try to verify its checksum, but the header + // itself is no longer required + std::optional content_md5_bin; - std::string content_md5_bin; - try { - content_md5_bin = rgw::from_base64(std::string_view(content_md5)); - } catch (...) { - s->err.message = "Request header Content-MD5 contains character " - "that is not base64 encoded."; - ldpp_dout(this, 5) << s->err.message << dendl; - op_ret = -ERR_BAD_DIGEST; - return; + content_md5 = s->info.env->get("HTTP_CONTENT_MD5"); + if (content_md5 != nullptr) { + try { + content_md5_bin = rgw::from_base64(std::string_view(content_md5)); + } catch (...) { + s->err.message = "Request header Content-MD5 contains character " + "that is not base64 encoded."; + ldpp_dout(this, 5) << s->err.message << dendl; + op_ret = -ERR_BAD_DIGEST; + return; + } } if (!parser.init()) { @@ -5828,21 +5828,23 @@ void RGWPutLC::execute(optional_yield y) char* buf = data.c_str(); ldpp_dout(this, 15) << "read len=" << data.length() << " data=" << (buf ? buf : "") << dendl; - MD5 data_hash; - // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes - data_hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); - unsigned char data_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE]; - data_hash.Update(reinterpret_cast(buf), data.length()); - data_hash.Final(data_hash_res); + if (content_md5_bin) { + MD5 data_hash; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + data_hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + unsigned char data_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE]; + data_hash.Update(reinterpret_cast(buf), data.length()); + data_hash.Final(data_hash_res); - if (memcmp(data_hash_res, content_md5_bin.c_str(), CEPH_CRYPTO_MD5_DIGESTSIZE) != 0) { - op_ret = -ERR_BAD_DIGEST; - s->err.message = "The Content-MD5 you specified did not match what we received."; - ldpp_dout(this, 5) << s->err.message - << " Specified content md5: " << content_md5 - << ", calculated content md5: " << data_hash_res - << dendl; - return; + if (memcmp(data_hash_res, content_md5_bin->c_str(), CEPH_CRYPTO_MD5_DIGESTSIZE) != 0) { + op_ret = -ERR_BAD_DIGEST; + s->err.message = "The Content-MD5 you specified did not match what we received."; + ldpp_dout(this, 5) << s->err.message + << " Specified content md5: " << content_md5 + << ", calculated content md5: " << data_hash_res + << dendl; + return; + } } if (!parser.parse(buf, data.length(), 1)) { -- 2.39.5