From: Marcus Watts Date: Thu, 18 Sep 2025 04:59:53 +0000 (-0400) Subject: copy object encryption fixes - complete_multipart_upload w/ sse-c X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=68faaf532b7e1f1aec1cd7e1fe12d390da456f6a;p=ceph-ci.git copy object encryption fixes - complete_multipart_upload w/ sse-c complete_multipart_upload: the spec requires that the client provide the same values for sse-c as were used to initiate the upload. Verify the required paraemeters exist and match. XXX fixup merge w/ previous Resolves: rhbz#2394511 Fixes: https://tracker.ceph.com/issues/23264 Signed-off-by: Marcus Watts (cherry picked from commit a5b3ac39619d3c15f5fbed3cd8c564a1e2beaa59) --- diff --git a/src/rgw/rgw_crypt.cc b/src/rgw/rgw_crypt.cc index ed120006136..5970aad9d52 100644 --- a/src/rgw/rgw_crypt.cc +++ b/src/rgw/rgw_crypt.cc @@ -1522,11 +1522,47 @@ int rgw_s3_prepare_decrypt(req_state* s, map& attrs, std::map& crypt_http_responses) { - // RGWDecryptContext cb(s); + const char *req_cust_alg = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM"); + const char *req_cust_key = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY"); + const char *req_cust_key_md5 = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5"); std::string stored_mode = get_str_attribute(attrs, RGW_ATTR_CRYPT_MODE); ldpp_dout(s, 15) << "Encryption mode: " << stored_mode << dendl; if (stored_mode == "SSE-C-AES256") { - auto keymd5 = to_base64(get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYMD5)); + auto keymd5_bin = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYMD5); + auto keymd5 = to_base64(keymd5_bin); + std::string key_bin; + MD5 key_hash; + + if (!req_cust_alg || strcmp(req_cust_alg, "AES256") + || !req_cust_key || !req_cust_key_md5 + || strcmp(req_cust_key_md5, keymd5.c_str()) ) { + s->err.message = "sse-c parameters do not match initial values"; + return -EINVAL; + } + + try { + key_bin = from_base64(req_cust_key); + } catch (...) { + ldpp_dout(s, 5) << "ERROR: invalid sse-c encryption " + << "key which contains character that is not base64 encoded." + << dendl; + s->err.message = "Requests specifying Server Side Encryption with Customer " + "provided keys must provide an appropriate secret key."; + return -EINVAL; + } + + // Allow use of MD5 digest in FIPS mode for non-cryptographic purposes + key_hash.SetFlags(EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + unsigned char key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE]; + key_hash.Update(reinterpret_cast(key_bin.c_str()), key_bin.size()); + key_hash.Final(key_hash_res); + + if (memcmp(key_hash_res, keymd5_bin.c_str(), CEPH_CRYPTO_MD5_DIGESTSIZE) != 0) { + ldpp_dout(s, 5) << "ERROR: Invalid key md5 hash" << dendl; + s->err.message = "The calculated MD5 hash of the key did not match the hash that was provided."; + return -EINVAL; + } + crypt_http_responses["x-amz-server-side-encryption-customer-algorithm"] = "AES256"; crypt_http_responses["x-amz-server-side-encryption-customer-key-MD5"] = keymd5; return 0; diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 06f5e036b7b..68b4b0c2b5b 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -7585,7 +7585,11 @@ void RGWCompleteMultipart::execute(optional_yield y) auto& target_attrs = meta_obj->get_attrs(); - (void) rgw_s3_prepare_decrypt(s, target_attrs, crypt_http_responses); + op_ret = rgw_s3_prepare_decrypt(s, target_attrs, crypt_http_responses); + if (op_ret < 0) { + ldpp_dout(this, 16) << "ERROR: incosistent crypto ret=" << op_ret << dendl; + return; + } if (cksum) { /* validate computed checksum against supplied checksum, if present */