From b5bc47b321ad1724e4e4f62297108f02eb9ea409 Mon Sep 17 00:00:00 2001 From: Mark Kogan Date: Tue, 12 Oct 2021 14:07:54 +0000 Subject: [PATCH] rgw: under fips, set flag to allow md5 in select rgw ops Fixes: https://tracker.ceph.com/issues/52900 Signed-off-by: Mark Kogan (cherry picked from commit a5df0cfcbe9b04832095f1f8ef0ce9f178888efd) --- src/common/ceph_crypto.cc | 5 +++++ src/common/ceph_crypto.h | 1 + src/rgw/rgw_bucket.cc | 2 ++ src/rgw/rgw_etag_verifier.h | 10 ++++++++-- src/rgw/rgw_file.h | 2 ++ src/rgw/rgw_op.cc | 34 +++++++++++++++++++++++---------- src/rgw/rgw_putobj_processor.cc | 2 ++ src/rgw/rgw_rados.cc | 2 ++ src/rgw/rgw_rest_swift.cc | 2 ++ src/rgw/rgw_tools.h | 7 ++++++- src/rgw/rgw_zone.cc | 2 ++ src/rgw/services/svc_zone.cc | 2 ++ 12 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/common/ceph_crypto.cc b/src/common/ceph_crypto.cc index cbeb1b06df615..e1f8705c9e654 100644 --- a/src/common/ceph_crypto.cc +++ b/src/common/ceph_crypto.cc @@ -196,6 +196,11 @@ void ssl::OpenSSLDigest::Restart() { EVP_DigestInit_ex(mpContext, mpType, NULL); } +void ssl::OpenSSLDigest::SetFlags(int flags) { + EVP_MD_CTX_set_flags(mpContext, flags); + this->Restart(); +} + void ssl::OpenSSLDigest::Update(const unsigned char *input, size_t length) { if (length) { EVP_DigestUpdate(mpContext, const_cast(reinterpret_cast(input)), length); diff --git a/src/common/ceph_crypto.h b/src/common/ceph_crypto.h index 6bf344aa8f13f..2feced03a99a5 100644 --- a/src/common/ceph_crypto.h +++ b/src/common/ceph_crypto.h @@ -52,6 +52,7 @@ namespace TOPNSPC::crypto { OpenSSLDigest (const EVP_MD *_type); ~OpenSSLDigest (); void Restart(); + void SetFlags(int flags); void Update (const unsigned char *input, size_t length); void Final (unsigned char *digest); }; diff --git a/src/rgw/rgw_bucket.cc b/src/rgw/rgw_bucket.cc index 054de08e172a8..4d9a9bc0877ef 100644 --- a/src/rgw/rgw_bucket.cc +++ b/src/rgw/rgw_bucket.cc @@ -2719,6 +2719,8 @@ static void get_md5_digest(const RGWBucketEntryPoint *be, string& md5_digest) { f->flush(bl); MD5 hash; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); hash.Update((const unsigned char *)bl.c_str(), bl.length()); hash.Final(m); diff --git a/src/rgw/rgw_etag_verifier.h b/src/rgw/rgw_etag_verifier.h index 7e2579b92c97b..8197fb872a1ec 100644 --- a/src/rgw/rgw_etag_verifier.h +++ b/src/rgw/rgw_etag_verifier.h @@ -30,7 +30,10 @@ protected: public: ETagVerifier(CephContext* cct_, rgw::putobj::DataProcessor *next) - : Pipe(next), cct(cct_) {} + : Pipe(next), cct(cct_) { + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + } virtual void calculate_etag() = 0; string get_calculated_etag() { return calculated_etag;} @@ -62,7 +65,10 @@ public: rgw::putobj::DataProcessor *next) : ETagVerifier(cct, next), part_ofs(std::move(part_ofs)) - {} + { + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + } int process(bufferlist&& data, uint64_t logical_offset) override; void calculate_etag() override; diff --git a/src/rgw/rgw_file.h b/src/rgw/rgw_file.h index ac8ada0251f5f..f3ec1e885c1df 100644 --- a/src/rgw/rgw_file.h +++ b/src/rgw/rgw_file.h @@ -2540,6 +2540,8 @@ public: ret = init_from_header(get_state()); } op = this; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); } bool only_bucket() override { return true; } diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 7dc50a6ce1c79..2339dccb7fd0e 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -794,7 +794,7 @@ int rgw_build_object_policies(rgw::sal::RGWRadosStore *store, struct req_state * } s->object_acl = std::make_unique(s->cct); rgw_obj obj(s->bucket, s->object); - + store->getRados()->set_atomic(s->obj_ctx, obj); if (prefetch_data) { store->getRados()->set_prefetch_data(s->obj_ctx, obj); @@ -1203,7 +1203,7 @@ void RGWGetBucketTags::pre_exec() rgw_bucket_object_pre_exec(s); } -void RGWGetBucketTags::execute() +void RGWGetBucketTags::execute() { auto iter = s->bucket_attrs.find(RGW_ATTR_TAGS); if (iter != s->bucket_attrs.end()) { @@ -1735,6 +1735,8 @@ static int iterate_user_manifest_parts(CephContext * const cct, list_op.params.delim = delim; MD5 etag_sum; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + etag_sum.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); do { #define MAX_LIST_OBJS 100 int r = list_op.list_objects(MAX_LIST_OBJS, &objs, NULL, &is_truncated, null_yield); @@ -2017,6 +2019,8 @@ int RGWGetObj::handle_slo_manifest(bufferlist& bl) map slo_parts; MD5 etag_sum; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + etag_sum.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); total_len = 0; for (const auto& entry : slo_info.entries) { @@ -2835,7 +2839,7 @@ void RGWDeleteBucketWebsite::execute() bufferlist in_data; op_ret = forward_request_to_master(s, nullptr, store, in_data, nullptr); if (op_ret < 0) { - ldpp_dout(this, 0) << "NOTICE: forward_to_master failed on bucket=" << s->bucket.name + ldpp_dout(this, 0) << "NOTICE: forward_to_master failed on bucket=" << s->bucket.name << "returned err=" << op_ret << dendl; return; } @@ -3534,7 +3538,7 @@ void RGWDeleteBucket::execute() if ( op_ret < 0) { ldpp_dout(this, 1) << "WARNING: failed to sync user stats before bucket delete: op_ret= " << op_ret << dendl; } - + op_ret = store->getRados()->check_bucket_empty(s->bucket_info, s->yield); if (op_ret < 0) { return; @@ -3847,6 +3851,8 @@ void RGWPutObj::execute() char calc_md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1]; unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE]; MD5 hash; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); bufferlist bl, aclbl, bs; int len; @@ -4274,6 +4280,8 @@ void RGWPostObj::execute() char calc_md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1]; unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE]; MD5 hash; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); ceph::buffer::list bl, aclbl; int len = 0; @@ -5607,6 +5615,8 @@ void RGWPutLC::execute() 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); @@ -5972,7 +5982,7 @@ void RGWInitMultipart::execute() op_ret = obj_op.write_meta(bl.length(), 0, attrs, s->yield); } while (op_ret == -EEXIST); - + const auto ret = rgw::notify::publish(s, s->object, s->obj_size, ceph::real_clock::now(), attrs[RGW_ATTR_ETAG].to_str(), rgw::notify::ObjectCreatedPost, store); if (ret < 0) { ldpp_dout(this, 5) << "WARNING: publishing notification failed, with error: " << ret << dendl; @@ -6031,6 +6041,8 @@ void RGWCompleteMultipart::execute() map attrs; off_t ofs = 0; MD5 hash; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); char final_etag[CEPH_CRYPTO_MD5_DIGESTSIZE]; char final_etag_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 16]; bufferlist etag_bl; @@ -6196,9 +6208,9 @@ void RGWCompleteMultipart::execute() ldpp_dout(this, 0) << "ERROR: compression type was changed during multipart upload (" << cs_info.compression_type << ">>" << obj_part.cs_info.compression_type << ")" << dendl; op_ret = -ERR_INVALID_PART; - return; + return; } - + if (part_compressed) { int64_t new_ofs; // offset in compression data for new part if (cs_info.blocks.size() > 0) @@ -6212,7 +6224,7 @@ void RGWCompleteMultipart::execute() cb.len = block.len; cs_info.blocks.push_back(cb); new_ofs = cb.new_ofs + cb.len; - } + } if (!compressed) cs_info.compression_type = obj_part.cs_info.compression_type; cs_info.orig_size += obj_part.cs_info.orig_size; @@ -6286,7 +6298,7 @@ void RGWCompleteMultipart::execute() } else { ldpp_dout(this, 0) << "WARNING: failed to remove object " << meta_obj << dendl; } - + const auto ret = rgw::notify::publish(s, s->object, ofs, ceph::real_clock::now(), final_etag_str, rgw::notify::ObjectCreatedCompleteMultipartUpload, store); if (ret < 0) { @@ -6690,7 +6702,7 @@ void RGWDeleteMultiObj::execute() bufferlist etag_bl; const auto etag = obj_state->get_attr(RGW_ATTR_ETAG, etag_bl) ? etag_bl.to_str() : ""; - const auto ret = rgw::notify::publish(s, obj.key, obj_state->size, obj_state->mtime, etag, + const auto ret = rgw::notify::publish(s, obj.key, obj_state->size, obj_state->mtime, etag, del_op.result.delete_marker && s->object.instance.empty() ? rgw::notify::ObjectRemovedDeleteMarkerCreated : rgw::notify::ObjectRemovedDelete, store); if (ret < 0) { @@ -7288,6 +7300,8 @@ int RGWBulkUploadOp::handle_file(const boost::string_ref path, ssize_t len = 0; size_t ofs = 0; MD5 hash; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); do { ceph::bufferlist data; len = body.get_at_most(s->cct->_conf->rgw_max_chunk_size, data); diff --git a/src/rgw/rgw_putobj_processor.cc b/src/rgw/rgw_putobj_processor.cc index 02ab414e22ca7..b65af0358db51 100644 --- a/src/rgw/rgw_putobj_processor.cc +++ b/src/rgw/rgw_putobj_processor.cc @@ -639,6 +639,8 @@ int AppendObjectProcessor::complete(size_t accounted_size, const string &etag, c //calculate the etag if (!cur_etag.empty()) { MD5 hash; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); char petag[CEPH_CRYPTO_MD5_DIGESTSIZE]; char final_etag[CEPH_CRYPTO_MD5_DIGESTSIZE]; char final_etag_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 16]; diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index 7c4b2280965c8..a677613793fb4 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -5228,6 +5228,8 @@ static void generate_fake_tag(RGWRados *store, map& attrset, unsigned char md5[CEPH_CRYPTO_MD5_DIGESTSIZE]; char md5_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1]; MD5 hash; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); hash.Update((const unsigned char *)manifest_bl.c_str(), manifest_bl.length()); map::iterator iter = attrset.find(RGW_ATTR_ETAG); diff --git a/src/rgw/rgw_rest_swift.cc b/src/rgw/rgw_rest_swift.cc index db3bb717014d6..358b8d7fc182e 100644 --- a/src/rgw/rgw_rest_swift.cc +++ b/src/rgw/rgw_rest_swift.cc @@ -988,6 +988,8 @@ int RGWPutObj_ObjStore_SWIFT::get_params() } MD5 etag_sum; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + etag_sum.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); uint64_t total_size = 0; for (auto& entry : slo_info->entries) { etag_sum.Update((const unsigned char *)entry.etag.c_str(), diff --git a/src/rgw/rgw_tools.h b/src/rgw/rgw_tools.h index d49f39efa6eb9..9e4449a508231 100644 --- a/src/rgw/rgw_tools.h +++ b/src/rgw/rgw_tools.h @@ -111,7 +111,12 @@ class RGWEtag H hash; public: - RGWEtag() {} + RGWEtag() { + if constexpr (std::is_same_v) { + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + } + } void update(const char *buf, size_t len) { hash.Update((const unsigned char *)buf, len); diff --git a/src/rgw/rgw_zone.cc b/src/rgw/rgw_zone.cc index 34c00014ad31e..c3bf462500ffc 100644 --- a/src/rgw/rgw_zone.cc +++ b/src/rgw/rgw_zone.cc @@ -1800,6 +1800,8 @@ static uint32_t gen_short_zone_id(const std::string zone_id) { unsigned char md5[CEPH_CRYPTO_MD5_DIGESTSIZE]; MD5 hash; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); hash.Update((const unsigned char *)zone_id.c_str(), zone_id.size()); hash.Final(md5); diff --git a/src/rgw/services/svc_zone.cc b/src/rgw/services/svc_zone.cc index df5386930512b..a30d2c9395314 100644 --- a/src/rgw/services/svc_zone.cc +++ b/src/rgw/services/svc_zone.cc @@ -434,6 +434,8 @@ int RGWSI_Zone::replace_region_with_zonegroup() unsigned char md5[CEPH_CRYPTO_MD5_DIGESTSIZE]; char md5_str[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1]; MD5 hash; + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); hash.Update((const unsigned char *)new_realm_name.c_str(), new_realm_name.length()); hash.Final(md5); buf_to_hex(md5, CEPH_CRYPTO_MD5_DIGESTSIZE, md5_str); -- 2.39.5