OPTION(rgw_keystone_admin_tenant, OPT_STR, "") // keystone admin user tenant (for keystone v2.0)
OPTION(rgw_keystone_admin_project, OPT_STR, "") // keystone admin user project (for keystone v3)
OPTION(rgw_keystone_admin_domain, OPT_STR, "") // keystone admin user domain
+OPTION(rgw_keystone_barbican_user, OPT_STR, "") // keystone user to access barbican secrets
+OPTION(rgw_keystone_barbican_password, OPT_STR, "") // keystone password for barbican user
+OPTION(rgw_keystone_barbican_tenant, OPT_STR, "") // keystone barbican user tenant (for keystone v2.0)
+OPTION(rgw_keystone_barbican_project, OPT_STR, "") // keystone barbican user project (for keystone v3)
+OPTION(rgw_keystone_barbican_domain, OPT_STR, "") // keystone barbican user domain
OPTION(rgw_keystone_api_version, OPT_INT, 2) // Version of Keystone API to use (2 or 3)
OPTION(rgw_keystone_accepted_roles, OPT_STR, "Member, admin") // roles required to serve requests
OPTION(rgw_keystone_accepted_admin_roles, OPT_STR, "") // list of roles allowing an user to gain admin privileges
OPTION(rgw_s3_auth_use_rados, OPT_BOOL, true) // should we try to use the internal credentials for s3?
OPTION(rgw_s3_auth_use_keystone, OPT_BOOL, false) // should we try to use keystone for s3?
OPTION(rgw_s3_auth_aws4_force_boto2_compat, OPT_BOOL, true) // force aws4 auth boto2 compatibility
+OPTION(rgw_barbican_url, OPT_STR, "") // url for barbican server
/* OpenLDAP-style LDAP parameter strings */
/* rgw_ldap_uri space-separated list of LDAP servers in URI format */
inline std::string from_base64(boost::string_ref sref)
{
using namespace boost::archive::iterators;
-
+ if (sref.empty())
+ return std::string();
/* MIME-compliant input will have line-breaks, so we have to
* filter WS */
typedef
#include <crypto++/cryptlib.h>
#include <crypto++/modes.h>
#include <crypto++/aes.h>
+#include <auth/Crypto.h>
+#include <rgw/rgw_b64.h>
+#include <rgw/rgw_rest_s3.h>
+#include "include/assert.h"
+#include <boost/utility/string_ref.hpp>
+#include <rgw/rgw_keystone.h>
#define dout_subsys ceph_subsys_rgw
using namespace CryptoPP;
+using namespace rgw;
class AES_256_CTR_impl {
static const size_t AES_256_KEYSIZE = 256 / 8;
}
std::string create_random_key_selector() {
- return "0123456789012345";
+ char random[AES_256_KEYSIZE];
+ if (get_random_bytes(&random[0], sizeof(random)) != 0) {
+ dout(0) << "ERROR: cannot get_random_bytes. " << dendl;
+ for (char& v:random) v=rand();
+ }
+ return std::string(random, sizeof(random));
}
-int get_actual_key_from_kms(CephContext *cct, const char* key_id, const std::string& key_selector, std::string& actual_key) {
- actual_key = "abcdefghijabcdef";
+
+//-H "Accept: application/octet-stream" -H "X-Auth-Token: fa7067ae04e942fb879eaf37f46411a5"
+//curl -v -H "Accept: application/octet-stream" -H "X-Auth-Token: fa7067ae04e942fb879eaf37f46411a5" http://localhost:9311/v1/secrets/5206dbad-7970-4a7a-82de-bd7df9a016db
+
+int get_barbican_url(CephContext * const cct,
+ std::string& url)
+{
+ url = cct->_conf->rgw_barbican_url;
+ if (url.empty()) {
+ ldout(cct, 0) << "ERROR: conf rgw_barbican_url is not set" << dendl;
+ return -EINVAL;
+ }
+
+ if (url[url.size() - 1] != '/') {
+ url.append("/");
+ }
+
return 0;
}
+int request_key_from_barbican(CephContext *cct,
+ boost::string_ref key_id,
+ boost::string_ref key_selector,
+ const std::string& barbican_token,
+ std::string& actual_key) {
+ std::string secret_url;
+ if (get_barbican_url(cct, secret_url) < 0) {
+ return -EINVAL;
+ }
+ secret_url += "v1/secrets/" + std::string(key_id);
+
+ int res;
+ bufferlist secret_bl;
+ RGWHTTPTransceiver secret_req(cct, &secret_bl);
+ secret_req.append_header("Accept", "application/octet-stream");
+ secret_req.append_header("X-Auth-Token", barbican_token);
+
+ res = secret_req.process("GET", secret_url.c_str());
+ if (res < 0) {
+ return res;
+ }
+ if (secret_req.get_http_status() ==
+ RGWHTTPTransceiver::HTTP_STATUS_UNAUTHORIZED) {
+ return -EACCES;
+ }
+
+ if (secret_req.get_http_status() >=200 &&
+ secret_req.get_http_status() < 300 &&
+ secret_bl.length() == AES_256_KEYSIZE) {
+ actual_key = std::string(secret_bl.c_str(), secret_bl.length());
+ } else {
+ res = -EACCES;
+ }
+ return res;
+}
+
+
+int get_actual_key_from_kms(CephContext *cct, boost::string_ref key_id, boost::string_ref key_selector, std::string& actual_key)
+{
+ int res = 0;
+ ldout(cct, 20) << "Getting KMS encryption key for key=" << key_id << dendl;
+ if (key_id.starts_with("testkey-")) {
+ /* test keys for testing purposes */
+ boost::string_ref key = key_id.substr(sizeof("testkey-")-1);
+ std::string master_key;
+ if (key == "1") master_key = "012345678901234567890123456789012345";
+ else if (key == "2") master_key = "abcdefghijklmnopqrstuvwxyzabcdefghij";
+ else {
+ res = -EIO;
+ return res;
+ }
+ uint8_t _actual_key[AES_256_KEYSIZE];
+ if (AES_256_ECB_encrypt((uint8_t*)master_key.c_str(), AES_256_KEYSIZE,
+ (uint8_t*)key_selector.data(),
+ _actual_key, AES_256_KEYSIZE)) {
+ actual_key = std::string((char*)&_actual_key[0], AES_256_KEYSIZE);
+ } else {
+ res = -EIO;
+ }
+ }
+ else {
+ std::string token;
+ if (rgw::keystone::Service::get_keystone_barbican_token(cct, token) < 0) {
+ ldout(cct, 20) << "Failed to retrieve token for barbican" << dendl;
+ res = -EINVAL;
+ return res;
+ }
+
+ res = request_key_from_barbican(cct, key_id, key_selector, token, actual_key);
+ if (res != 0) {
+ ldout(cct, 0) << "Failed to retrieve secret from barbican:" << key_id << dendl;
+ }
+ }
+ return res;
+}
+
+static inline void set_attr(map<string, bufferlist>& attrs, const char* key, const std::string& value)
+{
+ bufferlist bl;
+ ::encode(value,bl);
+ attrs.emplace(key, std::move(bl));
+}
+
+static inline void set_attr(map<string, bufferlist>& attrs, const char* key, const char* value)
+{
+ bufferlist bl;
+ ::encode(value,bl);
+ attrs.emplace(key, std::move(bl));
+}
+
+static inline void set_attr(map<string, bufferlist>& attrs, const char* key, boost::string_ref value)
+{
+ bufferlist bl;
+ __u32 len = value.length();
+ encode(len, bl);
+ if (len)
+ bl.append(value.data(), len);
+ attrs.emplace(key, std::move(bl));
+}
+
+static inline std::string get_str_attribute(map<string, bufferlist>& attrs, const std::string& name, const std::string& default_value="") {
+ std::string value;
+ auto iter = attrs.find(name);
+ if (iter == attrs.end() ) {
+ value = default_value;
+ } else {
+ try {
+ ::decode(value, iter->second);
+ } catch (buffer::error& err) {
+ value = default_value;
+ dout(0) << "ERROR: failed to decode attr:" << name << dendl;
+ }
+ }
+ return value;
+}
+
+typedef enum {
+ X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM=0,
+ X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY,
+ X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5,
+ X_AMZ_SERVER_SIDE_ENCRYPTION,
+ X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID,
+ X_AMZ_SERVER_SIDE_ENCRYPTION_LAST
+} crypt_option_e;
+
+typedef struct {
+ const char* http_header_name;
+ const std::string post_part_name;
+} crypt_option_names;
+
+static const crypt_option_names crypt_options[] = {
+ {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", "x-amz-server-side-encryption-customer-algorithm"},
+ {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", "x-amz-server-side-encryption-customer-key"},
+ {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "x-amz-server-side-encryption-customer-key-md5"},
+ {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION", "x-amz-server-side-encryption"},
+ {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID", "x-amz-server-side-encryption-aws-kms-key-id"},
+};
+
+boost::string_ref rgw_trim_whitespace(const boost::string_ref& src)
+{
+ if (src.empty()) {
+ return boost::string_ref();
+ }
+
+ int start = 0;
+ for (; start != (int)src.size(); start++) {
+ if (!isspace(src[start]))
+ break;
+ }
+
+ int end = src.size() - 1;
+ if (end < start) {
+ return boost::string_ref();
+ }
+
+ for (; end > start; end--) {
+ if (!isspace(src[end]))
+ break;
+ }
+
+ return src.substr(start, end - start + 1);
+}
+
+static boost::string_ref get_crypt_attribute(RGWEnv* env,
+ map<string, post_form_part, const ltstr_nocase>* parts,
+ crypt_option_e option)
+{
+ static_assert(X_AMZ_SERVER_SIDE_ENCRYPTION_LAST == sizeof(crypt_options)/sizeof(*crypt_options), "Missing items in crypt_options");
+ if (parts != nullptr) {
+ map<string, struct post_form_part, ltstr_nocase>::iterator iter
+ = parts->find(crypt_options[option].post_part_name);
+ if (iter == parts->end())
+ return boost::string_ref();
+ bufferlist& data = iter->second.data;
+ boost::string_ref str = boost::string_ref(data.c_str(), data.length());
+ return rgw_trim_whitespace(str);
+ } else {
+ const char* hdr = env->get(crypt_options[option].http_header_name, nullptr);
+ if (hdr != nullptr) {
+ return boost::string_ref(hdr);
+ } else {
+ return boost::string_ref();
+ }
+ }
+}
+
+int s3_prepare_encrypt(struct req_state* s,
+ map<string, bufferlist>& attrs,
+ map<string, post_form_part, const ltstr_nocase>* parts,
+ BlockCrypt** block_crypt,
+ std::string& crypt_http_responses)
+{
+ int res = 0;
+ crypt_http_responses = "";
+ if (block_crypt) *block_crypt = nullptr;
+ {
+ boost::string_ref req_sse_ca =
+ get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM);
+ if (! req_sse_ca.empty()) {
+ if (req_sse_ca != "AES256") {
+ res = -ERR_INVALID_REQUEST;
+ goto done;
+ }
+ std::string key_bin = from_base64(
+ get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY) );
+ if (key_bin.size() != AES_256_CTR::AES_256_KEYSIZE) {
+ res = -ERR_INVALID_REQUEST;
+ goto done;
+ }
+ boost::string_ref keymd5 =
+ get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5);
+ std::string keymd5_bin = from_base64(keymd5);
+ if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
+ res = -ERR_INVALID_DIGEST;
+ goto done;
+ }
+ MD5 key_hash;
+ uint8_t key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE];
+ key_hash.Update((uint8_t*)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) {
+ res = -ERR_INVALID_DIGEST;
+ goto done;
+ }
+
+ set_attr(attrs, RGW_ATTR_CRYPT_MODE, "SSE-C-AES256");
+ set_attr(attrs, RGW_ATTR_CRYPT_KEYMD5, keymd5_bin);
+
+ if (block_crypt) {
+ AES_256_CTR* aes = new AES_256_CTR(s->cct);
+ aes->set_key(reinterpret_cast<const uint8_t*>(key_bin.c_str()), AES_256_KEYSIZE);
+ *block_crypt = aes;
+ }
+
+ crypt_http_responses =
+ "x-amz-server-side-encryption-customer-algorithm: AES256\r\n"
+ "x-amz-server-side-encryption-customer-key-MD5: " + std::string(keymd5) + "\r\n";
+ goto done;
+ }
+ /* AMAZON server side encryption with KMS (key management service) */
+ boost::string_ref req_sse =
+ get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION);
+ if (! req_sse.empty()) {
+ if (req_sse != "aws:kms") {
+ res = -ERR_INVALID_REQUEST;
+ goto done;
+ }
+ boost::string_ref key_id =
+ get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID);
+ if (key_id.empty()) {
+ /* TODO!!! retrieve key_id from bucket */
+ res = -ERR_INVALID_ACCESS_KEY;
+ goto done;
+ }
+ /* try to retrieve actual key */
+ std::string key_selector = create_random_key_selector();
+ std::string actual_key;
+ res = get_actual_key_from_kms(s->cct, key_id, key_selector, actual_key);
+ if (res != 0)
+ goto done;
+ if (actual_key.size() != AES_256_KEYSIZE) {
+ ldout(s->cct, 0) << "ERROR: key obtained from key_id:" <<
+ key_id << " is not 256 bit size" << dendl;
+ res = -ERR_INVALID_ACCESS_KEY;
+ goto done;
+ }
+ set_attr(attrs, RGW_ATTR_CRYPT_MODE, "SSE-KMS");
+ set_attr(attrs, RGW_ATTR_CRYPT_KEYID, key_id);
+ set_attr(attrs, RGW_ATTR_CRYPT_KEYSEL, key_selector);
+
+ if (block_crypt) {
+ AES_256_CTR* aes = new AES_256_CTR(s->cct);
+ aes->set_key(reinterpret_cast<const uint8_t*>(actual_key.c_str()), AES_256_KEYSIZE);
+ *block_crypt = aes;
+ }
+ goto done;
+ }
+
+ /* no other encryption mode, check if default encryption is selected */
+ if (s->cct->_conf->rgw_crypt_default_encryption_key != "") {
+ std::string master_encryption_key = from_base64(std::string(s->cct->_conf->rgw_crypt_default_encryption_key));
+ if (master_encryption_key.size() != 256 / 8) {
+ ldout(s->cct, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl;
+ /* not an error to return; missing encryption does not inhibit processing */
+ goto done;
+ }
+
+ set_attr(attrs, RGW_ATTR_CRYPT_MODE, "RGW-AUTO");
+ std::string key_selector = create_random_key_selector();
+ set_attr(attrs, RGW_ATTR_CRYPT_KEYSEL, key_selector);
+
+ uint8_t actual_key[AES_256_KEYSIZE];
+ if (AES_256_ECB_encrypt((uint8_t*)master_encryption_key.c_str(), AES_256_KEYSIZE,
+ (uint8_t*)key_selector.c_str(),
+ actual_key, AES_256_KEYSIZE) != true) {
+ res = -EIO;
+ goto done;
+ }
+ if (block_crypt) {
+ AES_256_CTR* aes = new AES_256_CTR(s->cct);
+ aes->set_key(actual_key, AES_256_KEYSIZE);
+ *block_crypt = aes;
+ }
+
+ goto done;
+ }
+ }
+ done:
+ return res;
+}
+
+int s3_prepare_decrypt(
+ struct req_state* s,
+ map<string, bufferlist>& attrs,
+ BlockCrypt** block_crypt,
+ std::map<std::string, std::string>& crypt_http_responses)
+{
+ int res = 0;
+ std::string stored_mode = get_str_attribute(attrs, RGW_ATTR_CRYPT_MODE);
+ ldout(s->cct, 15) << "Encryption mode: " << stored_mode << dendl;
+
+ if (stored_mode == "SSE-C-AES256") {
+ const char *req_cust_alg = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", NULL);
+ if ((nullptr == req_cust_alg) || (strcmp(req_cust_alg, "AES256") != 0)) {
+ res = -ERR_INVALID_REQUEST;
+ goto done;
+ }
+
+ std::string key_bin = from_base64(s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", ""));
+ if (key_bin.size() != AES_256_CTR::AES_256_KEYSIZE) {
+ res = -ERR_INVALID_REQUEST;
+ goto done;
+ }
+
+ std::string keymd5 = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "");
+ std::string keymd5_bin = from_base64(keymd5);
+ if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
+ res = -ERR_INVALID_DIGEST;
+ goto done;
+ }
+ MD5 key_hash;
+ uint8_t key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE];
+ key_hash.Update((uint8_t*)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) ||
+ (get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYMD5) != keymd5_bin)) {
+ res = -ERR_INVALID_DIGEST;
+ goto done;
+ }
+ AES_256_CTR* aes = new AES_256_CTR(s->cct);
+ aes->set_key((uint8_t*)key_bin.c_str(), AES_256_CTR::AES_256_KEYSIZE);
+ if (block_crypt) *block_crypt = aes;
+
+ crypt_http_responses =
+ "x-amz-server-side-encryption-customer-algorithm: AES256\r\n"
+ "x-amz-server-side-encryption-customer-key-MD5: " + keymd5 + "\r\n";
+ goto done;
+ }
+
+ if (stored_mode == "SSE-KMS") {
+ /* try to retrieve actual key */
+ std::string key_id = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYID);
+ std::string key_selector = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYSEL);
+ std::string actual_key;
+ res = get_actual_key_from_kms(s->cct, key_id, key_selector, actual_key);
+ if (res != 0) {
+ ldout(s->cct, 10) << "No encryption key for key-id=" << key_id << dendl;
+ goto done;
+ }
+ if (actual_key.size() != AES_256_KEYSIZE) {
+ ldout(s->cct, 0) << "ERROR: key obtained from key_id:" <<
+ key_id << " is not 256 bit size" << dendl;
+ res = -ERR_INVALID_ACCESS_KEY;
+ goto done;
+ }
+
+ AES_256_CTR* aes = new AES_256_CTR(s->cct);
+ aes->set_key(reinterpret_cast<const uint8_t*>(actual_key.c_str()), AES_256_KEYSIZE);
+
+ if (block_crypt) *block_crypt = aes;
+
+ crypt_http_responses =
+ "x-amz-server-side-encryption: aws:kms\r\n"
+ "x-amz-server-side-encryption-aws-kms-key-id: " + key_id + "\r\n";
+ goto done;
+ }
+
+ if (stored_mode == "RGW-AUTO") {
+ std::string master_encryption_key = from_base64(std::string(s->cct->_conf->rgw_crypt_default_encryption_key));
+ if (master_encryption_key.size() != 256 / 8) {
+ ldout(s->cct, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl;
+ res = -EIO;
+ goto done;
+ }
+ std::string attr_key_selector = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYSEL);
+ if (attr_key_selector.size() != AES_256_CTR::AES_256_KEYSIZE) {
+ ldout(s->cct, 0) << "ERROR: missing or invalid " RGW_ATTR_CRYPT_KEYSEL << dendl;
+ res = -EIO;
+ goto done;
+ }
+ uint8_t actual_key[AES_256_KEYSIZE];
+ if (AES_256_ECB_encrypt((uint8_t*)master_encryption_key.c_str(), AES_256_KEYSIZE,
+ (uint8_t*)attr_key_selector.c_str(),
+ actual_key, AES_256_KEYSIZE) != true) {
+ res = -EIO;
+ goto done;
+ }
+ AES_256_CTR* aes = new AES_256_CTR(s->cct);
+ aes->set_key(actual_key, AES_256_KEYSIZE);
+
+ if (block_crypt) *block_crypt = aes;
+ goto done;
+ }
+
+ done:
+ return res;
+}
#define CEPH_RGW_CRYPT_H
#include <rgw/rgw_op.h>
+#include <rgw/rgw_rest_s3.h>
+#include <boost/utility/string_ref.hpp>
class BlockCrypt {
public:
size_t block_size;
std::vector<size_t> parts_len;
public:
- RGWGetObj_BlockDecrypt(CephContext* cct, RGWGetDataCB& next, BlockCrypt* crypt);
+ RGWGetObj_BlockDecrypt(CephContext* cct, RGWGetDataCB* next, BlockCrypt* crypt);
virtual ~RGWGetObj_BlockDecrypt();
virtual int fixup_range(off_t& bl_ofs, off_t& bl_end) override;
bufferlist cache;
size_t block_size;
public:
- RGWPutObj_BlockEncrypt(CephContext* cct, RGWPutObjDataProcessor& next, BlockCrypt* crypt);
+ RGWPutObj_BlockEncrypt(CephContext* cct, RGWPutObjDataProcessor* next, BlockCrypt* crypt);
virtual ~RGWPutObj_BlockEncrypt();
virtual int handle_data(bufferlist& bl, off_t ofs, void **phandle, rgw_obj *pobj, bool *again) override;
virtual int throttle_data(void *handle, const rgw_obj& obj, uint64_t size, bool need_to_wait) override;
}; /* RGWPutObj_BlockEncrypt */
std::string create_random_key_selector();
-int get_actual_key_from_kms(CephContext *cct, const char* key_id, const std::string& key_selector, std::string& actual_key);
+//int get_actual_key_from_kms(CephContext *cct, const std::string& key_id, const std::string& key_selector, std::string& actual_key);
+int get_actual_key_from_kms(CephContext *cct, boost::string_ref key_id, boost::string_ref key_selector, std::string& actual_key);
+
+int s3_prepare_encrypt(struct req_state* s,
+ map<string, bufferlist>& attrs,
+ map<string, post_form_part, const ltstr_nocase>* parts,
+ BlockCrypt** block_crypt,
+ std::map<std::string, std::string>& crypt_http_responses);
+int s3_prepare_decrypt(struct req_state* s,
+ map<string, bufferlist>& attrs,
+ BlockCrypt** block_crypt,
+ std::map<std::string, std::string>& crypt_http_responses);
#endif
}
+void rgw::keystone::BarbicanTokenRequestVer2::dump(Formatter* const f) const
+{
+ f->open_object_section("token_request");
+ f->open_object_section("auth");
+ f->open_object_section("passwordCredentials");
+ encode_json("username", cct->_conf->rgw_keystone_barbican_user, f);
+ encode_json("password", cct->_conf->rgw_keystone_barbican_password, f);
+ f->close_section();
+ encode_json("tenantName", cct->_conf->rgw_keystone_barbican_tenant, f);
+ f->close_section();
+ f->close_section();
+}
+
+void rgw::keystone::BarbicanTokenRequestVer3::dump(Formatter* const f) const
+{
+ f->open_object_section("token_request");
+ f->open_object_section("auth");
+ f->open_object_section("identity");
+ f->open_array_section("methods");
+ f->dump_string("", "password");
+ f->close_section();
+ f->open_object_section("password");
+ f->open_object_section("user");
+ f->open_object_section("domain");
+ encode_json("name", cct->_conf->rgw_keystone_barbican_domain, f);
+ f->close_section();
+ encode_json("name", cct->_conf->rgw_keystone_barbican_user, f);
+ encode_json("password", cct->_conf->rgw_keystone_barbican_password, f);
+ f->close_section();
+ f->close_section();
+ f->close_section();
+ f->open_object_section("scope");
+ f->open_object_section("project");
+ if (!cct->_conf->rgw_keystone_barbican_project.empty()) {
+ encode_json("name", cct->_conf->rgw_keystone_barbican_project, f);
+ } else {
+ encode_json("name", cct->_conf->rgw_keystone_barbican_tenant, f);
+ }
+ f->open_object_section("domain");
+ encode_json("name", cct->_conf->rgw_keystone_barbican_domain, f);
+ f->close_section();
+ f->close_section();
+ f->close_section();
+ f->close_section();
+ f->close_section();
+}
+
void RGWOrphanSearchStage::dump(Formatter *f) const
{
f->open_object_section("orphan_search_stage");
return 0;
}
+int Service::get_keystone_barbican_token(CephContext * const cct,
+ std::string& token)
+{
+ using keystone_config_t = rgw::keystone::CephCtxConfig;
+ using keystone_cache_t = rgw::keystone::TokenCache;
+
+ auto& config = keystone_config_t::get_instance();
+ auto& token_cache = keystone_cache_t::get_instance<keystone_config_t>();
+
+ std::string token_url = config.get_endpoint_url();
+ if (token_url.empty()) {
+ return -EINVAL;
+ }
+
+ rgw::keystone::TokenEnvelope t;
+
+ /* Try cache first. */
+ if (token_cache.find_barbican(t)) {
+ ldout(cct, 20) << "found cached barbican token" << dendl;
+ token = t.token.id;
+ return 0;
+ }
+
+ bufferlist token_bl;
+ RGWKeystoneHTTPTransceiver token_req(cct, &token_bl);
+ token_req.append_header("Content-Type", "application/json");
+ JSONFormatter jf;
+
+ const auto keystone_version = config.get_api_version();
+ if (keystone_version == ApiVersion::VER_2) {
+ rgw::keystone::BarbicanTokenRequestVer2 req_serializer(cct);
+ req_serializer.dump(&jf);
+
+ std::stringstream ss;
+ jf.flush(ss);
+ token_req.set_post_data(ss.str());
+ token_req.set_send_length(ss.str().length());
+ token_url.append("v2.0/tokens");
+
+ } else if (keystone_version == ApiVersion::VER_3) {
+ BarbicanTokenRequestVer3 req_serializer(cct);
+ req_serializer.dump(&jf);
+
+ std::stringstream ss;
+ jf.flush(ss);
+ token_req.set_post_data(ss.str());
+ token_req.set_send_length(ss.str().length());
+ token_url.append("v3/auth/tokens");
+ } else {
+ return -ENOTSUP;
+ }
+
+ ldout(cct, 20) << "Requesting secret from barbican url=" << token_url << dendl;
+ const int ret = token_req.process("POST", token_url.c_str());
+ if (ret < 0) {
+ ldout(cct, 20) << "Barbican process error:" << token_bl.c_str() << dendl;
+ return ret;
+ }
+
+ /* Detect rejection earlier than during the token parsing step. */
+ if (token_req.get_http_status() ==
+ RGWKeystoneHTTPTransceiver::HTTP_STATUS_UNAUTHORIZED) {
+ return -EACCES;
+ }
+
+ if (t.parse(cct, token_req.get_subject_token(), token_bl,
+ keystone_version) != 0) {
+ return -EINVAL;
+ }
+
+ token_cache.add_barbican(t);
+ token = t.token.id;
+ return 0;
+}
+
bool TokenEnvelope::has_role(const std::string& r) const
{
return find_locked(admin_token_id, token);
}
+bool TokenCache::find_barbican(rgw::keystone::TokenEnvelope& token)
+{
+ Mutex::Locker l(lock);
+
+ return find(barbican_token_id, token);
+}
+
void TokenCache::add(const std::string& token_id,
const rgw::keystone::TokenEnvelope& token)
{
add_locked(admin_token_id, token);
}
+void TokenCache::add_barbican(const rgw::keystone::TokenEnvelope& token)
+{
+ Mutex::Locker l(lock);
+
+ rgw_get_token_id(token.token.id, barbican_token_id);
+ add(barbican_token_id, token);
+}
+
void TokenCache::invalidate(const std::string& token_id)
{
Mutex::Locker l(lock);
static int issue_admin_token_request(CephContext* const cct,
const Config& config,
TokenEnvelope& token);
+ static int get_keystone_barbican_token(CephContext * const cct,
+ std::string& token);
};
CephContext * const cct;
std::string admin_token_id;
+ std::string barbican_token_id;
std::map<std::string, token_entry> tokens;
std::list<std::string> tokens_lru;
return boost::none;
}
bool find_admin(TokenEnvelope& token);
+ bool find_barbican(TokenEnvelope& token);
void add(const std::string& token_id, const TokenEnvelope& token);
void add_admin(const TokenEnvelope& token);
+ void add_barbican(const TokenEnvelope& token);
void invalidate(const std::string& token_id);
bool going_down() const;
private:
void dump(Formatter *f) const override;
};
+class BarbicanTokenRequestVer2 : public AdminTokenRequest {
+ CephContext *cct;
+
+public:
+ BarbicanTokenRequestVer2(CephContext * const _cct)
+ : cct(_cct) {
+ }
+ void dump(Formatter *f) const;
+};
+
+class BarbicanTokenRequestVer3 : public AdminTokenRequest {
+ CephContext *cct;
+
+public:
+ BarbicanTokenRequestVer3(CephContext * const _cct)
+ : cct(_cct) {
+ }
+ void dump(Formatter *f) const;
+};
+
+
}; /* namespace keystone */
}; /* namespace rgw */
}
}
+ for (auto &it : crypt_http_responses)
+ dump_header(s, it.first, it.second);
+
dump_content_length(s, total_len);
dump_last_modified(s, lastmod);
int RGWGetObj_ObjStore_S3::get_decrypt_filter(RGWGetDataCB** filter, RGWGetDataCB* cb, bufferlist* manifest_bl)
{
int res = 0;
- *filter = nullptr;
- map<string, bufferlist>::iterator attr_iter;
- std::string attr_mode;
- std::string attr_md5;
- attr_iter = attrs.find(RGW_ATTR_CRYPT_MODE);
- if (attr_iter == attrs.end() ) {
- /* no encryption - no problem with that */
- goto done;
- }
- try {
- ::decode(attr_mode, attr_iter->second);
- } catch (buffer::error& err) {
- ldout(s->cct, 0) << "ERROR: failed to decode " RGW_ATTR_CRYPT_MODE << dendl;
- res = -EIO;
- goto done;
- }
- ldout(s->cct, 20) << "Encryption mode=" << attr_mode << dendl;
- if (attr_mode == "SSE-C-AES256") {
- const char *enc_customer = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", "");
- if (strcmp(enc_customer, "AES256") != 0) {
- ldout(s->cct, 10) << "ERROR. x-amz-server-side-encryption-customer-algorithm must be 'AES256'" << dendl;
- res = -ERR_INVALID_REQUEST;
- goto done;
- }
- const char* key = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", "");
- std::string key_bin = from_base64(key);
- if (key_bin.size() != AES_256_CTR::AES_256_KEYSIZE) {
- ldout(s->cct, 10) << "ERROR. x-amz-server-side-encryption-customer-key must decode to 256 bit key" << dendl;
- res = -ERR_INVALID_REQUEST;
- goto done;
- }
- const char* keymd5 = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "");
- std::string keymd5_bin = from_base64(keymd5);
- if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
- ldout(s->cct, 10) << "ERROR. x-amz-server-side-encryption-customer-key-md5 mismatches key" << dendl;
- res = -ERR_INVALID_DIGEST;
- goto done;
- }
-
- MD5 key_hash;
- uint8_t key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE];
- key_hash.Update((uint8_t*)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) {
- ldout(s->cct, 20) << "MD5 failed" << dendl;
- res = -ERR_INVALID_DIGEST;
- goto done;
- }
- attr_iter = attrs.find(RGW_ATTR_CRYPT_KEYMD5);
- if (attr_iter == attrs.end()) {
- res = - ERR_INVALID_DIGEST;
- goto done;
- }
- try {
- ::decode(attr_md5, attr_iter->second);
- }
- catch (buffer::error& err) {
- ldout(s->cct, 0) << "ERROR: failed to decode" RGW_ATTR_CRYPT_KEYMD5 << dendl;
- res = -EIO;
- goto done;
- }
- if (attr_md5 != keymd5_bin) {
- ldout(s->cct, 20) << "MD5 from " RGW_ATTR_CRYPT_KEYMD5 " mismatches x-amz-server-side-encryption-customer-key-md5" << dendl;
- res = - ERR_INVALID_DIGEST;
- goto done;
- }
-
- AES_256_CTR* aes=new AES_256_CTR(s->cct);
- aes->set_key((uint8_t*)key_bin.c_str(), AES_256_CTR::AES_256_KEYSIZE);
-
- RGWGetObj_BlockDecrypt* f =new RGWGetObj_BlockDecrypt(s->cct, /*manifest_bl,*/ *cb, aes);
- if (f != nullptr) {
- res = f->read_manifest(*manifest_bl);
- if (res == 0) {
- *filter = f;
- } else {
- delete f;
- }
- }
- ldout(s->cct, 20) << "Created decryptor key." << dendl;
- goto done;
- }
-
- if (attr_mode == "RGW-AUTO") {
- std::string master_encryption_key = from_base64(/*std::string*/(s->cct->_conf->rgw_crypt_default_encryption_key));
- if (master_encryption_key.size() != 256 / 8) {
- ldout(s->cct, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl;
- /* not an error to return; missing encryption does not inhibit processing */
- res = -EIO;
- goto done;
- }
- std::string attr_key_selector;
- attr_iter = attrs.find(RGW_ATTR_CRYPT_KEYSEL);
- if (attr_iter == attrs.end()) {
- res = - EIO;
- goto done;
- }
- try {
- ::decode(attr_key_selector, attr_iter->second);
- //attr_key_selector = "abcdefghijabcdefghijabcdefghijab";
- }
- catch (buffer::error& err) {
- ldout(s->cct, 0) << "ERROR: failed to decode" RGW_ATTR_CRYPT_KEYMD5 << dendl;
- res = -EIO;
- goto done;
- }
- if (attr_key_selector.size() != AES_256_CTR::AES_256_KEYSIZE) {
- res = -EIO;
- goto done;
- }
-
- uint8_t actual_key[AES_256_KEYSIZE];
- if (AES_256_ECB_encrypt((uint8_t*)master_encryption_key.c_str(), AES_256_KEYSIZE,
- (uint8_t*)attr_key_selector.c_str(),
- actual_key, AES_256_KEYSIZE) != true) {
- res = -EIO;
- goto done;
- }
-
- AES_256_CTR* aes=new AES_256_CTR(s->cct);
- aes->set_key(actual_key, AES_256_KEYSIZE);
-
- RGWGetObj_BlockDecrypt* f =new RGWGetObj_BlockDecrypt(s->cct, /*manifest_bl,*/ *cb, aes);
- if (f != nullptr) {
- if (manifest_bl != nullptr)
- res = f->read_manifest(*manifest_bl);
- if (res == 0) {
- *filter = f;
- } else {
- delete f;
+ BlockCrypt* block_crypt = nullptr;
+ res = s3_prepare_decrypt(s, attrs, &block_crypt, crypt_http_responses);
+ if (res == 0) {
+ if (block_crypt != nullptr) {
+ RGWGetObj_BlockDecrypt* f = new RGWGetObj_BlockDecrypt(s->cct, cb, block_crypt);
+ if (f != nullptr) {
+ if (manifest_bl != nullptr)
+ res = f->read_manifest(*manifest_bl);
+ if (res == 0) {
+ *filter = f;
+ } else {
+ delete f;
+ }
}
}
- ldout(s->cct, 20) << "Created decryptor key." << dendl;
- goto done;
}
- done:
return res;
}
return 0;
}
-static std::string get_str_attribute(map<string, bufferlist>& attrs, const std::string& name, const std::string& default_value="") {
- std::string value;
- auto iter = attrs.find(name);
- if (iter == attrs.end() ) {
- value = default_value;
- } else {
- try {
- ::decode(value, iter->second);
- } catch (buffer::error& err) {
- value = default_value;
- dout(0) << "ERROR: failed to decode attr:" << name << dendl;
- }
- }
- return value;
-}
-
void RGWPutObj_ObjStore_S3::send_response()
{
if (op_ret) {
int RGWPutObj_ObjStore_S3::get_encrypt_filter(RGWPutObjDataProcessor** filter, RGWPutObjDataProcessor* cb)
{
int res = 0;
- *filter = nullptr;
-
RGWPutObjProcessor_Multipart* multi_processor=dynamic_cast<RGWPutObjProcessor_Multipart*>(cb);
if (multi_processor != nullptr) {
RGWMPObj* mp = nullptr;
obj.init_ns(s->bucket, meta_oid, RGW_OBJ_NS_MULTIPART);
obj.set_in_extra_data(true);
res = get_obj_attrs(store, s, obj, xattrs);
- if (res != 0) {
- goto done;
- }
- std::string stored_mode = get_str_attribute(xattrs, RGW_ATTR_CRYPT_MODE);
- ldout(s->cct, 15) << "Multipart encryption mode: " << stored_mode << dendl;
-
- const char *req_cust_alg = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", NULL);
- if (stored_mode == "SSE-C-AES256") {
- if ((nullptr == req_cust_alg) || (strcmp(req_cust_alg, "AES256") != 0)) {
- res = -ERR_INVALID_REQUEST;
- goto done;
- }
-
- std::string key_bin = from_base64(s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", ""));
- if (key_bin.size() != AES_256_CTR::AES_256_KEYSIZE) {
- res = -ERR_INVALID_REQUEST;
- goto done;
- }
-
- std::string keymd5 = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "");
- std::string keymd5_bin = from_base64(keymd5);
- if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
- res = -ERR_INVALID_DIGEST;
- goto done;
- }
- MD5 key_hash;
- uint8_t key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE];
- key_hash.Update((uint8_t*)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) ||
- (get_str_attribute(xattrs, RGW_ATTR_CRYPT_KEYMD5) != keymd5_bin)) {
- res = -ERR_INVALID_DIGEST;
- goto done;
- }
- AES_256_CTR* aes=new AES_256_CTR(s->cct);
- aes->set_key((uint8_t*)key_bin.c_str(), AES_256_CTR::AES_256_KEYSIZE);
- *filter=new RGWPutObj_BlockEncrypt(s->cct, *cb, aes);
-
- crypt_http_responses["x-amz-server-side-encryption-customer-algorithm"] =
- "AES256";
- crypt_http_responses["x-amz-server-side-encryption-customer-key-MD5"] =
- keymd5;
- goto done;
- }
-
- if (stored_mode == "RGW-AUTO") {
- std::string master_encryption_key = from_base64(std::string(s->cct->_conf->rgw_crypt_default_encryption_key));
- if (master_encryption_key.size() != 256 / 8) {
- ldout(s->cct, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl;
- res = -EIO;
- goto done;
- }
- std::string attr_key_selector = get_str_attribute(xattrs, RGW_ATTR_CRYPT_KEYSEL);
- if (attr_key_selector.size() != AES_256_CTR::AES_256_KEYSIZE) {
- ldout(s->cct, 0) << "ERROR: missing or invalid " RGW_ATTR_CRYPT_KEYSEL << dendl;
- res = -EIO;
- goto done;
- }
- uint8_t actual_key[AES_256_KEYSIZE];
- if (AES_256_ECB_encrypt((uint8_t*)master_encryption_key.c_str(), AES_256_KEYSIZE,
- (uint8_t*)attr_key_selector.c_str(),
- actual_key, AES_256_KEYSIZE) != true) {
- res = -EIO;
- goto done;
- }
- AES_256_CTR* aes=new AES_256_CTR(s->cct);
- aes->set_key(actual_key, AES_256_KEYSIZE);
- *filter=new RGWPutObj_BlockEncrypt(s->cct, *cb, aes);
- goto done;
+ if (res == 0) {
+ BlockCrypt* block_crypt = nullptr;
+ res = s3_prepare_decrypt(s, xattrs, &block_crypt, crypt_http_responses);
+ if (res == 0 && block_crypt != nullptr)
+ *filter=new RGWPutObj_BlockEncrypt(s->cct, cb, block_crypt);
}
}
- /* no encryption at all for multipart*/
- goto done;
+ /* it is ok, to not have encryption at all */
}
else
{
- const char* req_sse = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", NULL);
- if (req_sse != NULL) {
- if (strcmp(req_sse, "AES256") != 0) {
- res = -ERR_INVALID_REQUEST;
- goto done;
- }
- const char* key = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", NULL);
- std::string key_bin = (key ? from_base64(key) : "");
- if (key_bin.size() != AES_256_CTR::AES_256_KEYSIZE) {
- res = -ERR_INVALID_REQUEST;
- goto done;
- }
- std::string keymd5 = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "");
- std::string keymd5_bin = from_base64(keymd5);
- if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
- res = -ERR_INVALID_DIGEST;
- goto done;
- }
- MD5 key_hash;
- uint8_t key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE];
- key_hash.Update((uint8_t*)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) {
- res = -ERR_INVALID_DIGEST;
- goto done;
- }
-
- set_attr(attrs, RGW_ATTR_CRYPT_MODE, "SSE-C-AES256");
- set_attr(attrs, RGW_ATTR_CRYPT_KEYMD5, keymd5_bin);
-
- AES_256_CTR* aes=new AES_256_CTR(s->cct);
- aes->set_key((uint8_t*)key_bin.c_str(), AES_256_CTR::AES_256_KEYSIZE);
- *filter=new RGWPutObj_BlockEncrypt(s->cct, *cb, aes);
- crypt_http_responses["x-amz-server-side-encryption-customer-algorithm"] =
- "AES256";
- crypt_http_responses["x-amz-server-side-encryption-customer-key-MD5"] =
- keymd5;
- goto done;
- }
-
- /* no other encryption mode, check if default encryption is selected */
- if (s->cct->_conf->rgw_crypt_default_encryption_key != "") {
- std::string master_encryption_key = from_base64(std::string(s->cct->_conf->rgw_crypt_default_encryption_key));
- if (master_encryption_key.size() != 256 / 8) {
- ldout(s->cct, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl;
- /* not an error to return; missing encryption does not inhibit processing */
- goto done;
- }
-
- set_attr(attrs, RGW_ATTR_CRYPT_MODE, "RGW-AUTO");
- std::string key_selector = create_random_key_selector();
- set_attr(attrs, RGW_ATTR_CRYPT_KEYSEL, key_selector);
-
- uint8_t actual_key[AES_256_KEYSIZE];
- if (AES_256_ECB_encrypt((uint8_t*)master_encryption_key.c_str(), AES_256_KEYSIZE,
- (uint8_t*)key_selector.c_str(),
- actual_key, AES_256_KEYSIZE) != true) {
- res = -EIO;
- goto done;
- }
- AES_256_CTR* aes=new AES_256_CTR(s->cct);
- aes->set_key(actual_key, AES_256_KEYSIZE);
- *filter=new RGWPutObj_BlockEncrypt(s->cct, *cb, aes);
- goto done;
+ BlockCrypt* block_crypt = nullptr;
+ res = s3_prepare_encrypt(s, attrs, nullptr, &block_crypt, crypt_http_responses);
+ if (res == 0 && block_crypt!=nullptr) {
+ *filter = new RGWPutObj_BlockEncrypt(s->cct, cb, block_crypt);
}
}
- done:
return res;
}
/*
done:
if (op_ret == STATUS_CREATED) {
+ for (auto &it : crypt_http_responses)
+ dump_header(s, it.first, it.second);
s->formatter->open_object_section("PostResponse");
if (g_conf->rgw_dns_name.length())
s->formatter->dump_format("Location", "%s/%s",
int RGWPostObj_ObjStore_S3::get_encrypt_filter(RGWPutObjDataProcessor** filter, RGWPutObjDataProcessor* cb)
{
int res = 0;
- *filter = nullptr;
- const char *enc_customer = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", NULL);
- if (enc_customer != NULL) {
- if (strcmp(enc_customer,"AES256") != 0) {
- res = -ERR_INVALID_REQUEST;
- goto done;
- }
- const char* key = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", NULL);
- std::string key_bin = from_base64(key);
- if (key_bin.size() != AES_256_CTR::AES_256_KEYSIZE) {
- res = -ERR_INVALID_REQUEST;
- goto done;
- }
- const char* keymd5 = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", NULL);
- std::string keymd5_bin = from_base64(keymd5);
- if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
- res = -ERR_INVALID_DIGEST;
- goto done;
- }
-
- MD5 key_hash;
- uint8_t key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE];
- key_hash.Update((uint8_t*)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) {
- res = -ERR_INVALID_DIGEST;
- goto done;
- }
-
- set_attr(attrs, RGW_ATTR_CRYPT_MODE, "SSE-C-AES256");
- set_attr(attrs, RGW_ATTR_CRYPT_KEYMD5, keymd5_bin);
-
- AES_256_CTR* aes=new AES_256_CTR(s->cct);
- aes->set_key((uint8_t*)key_bin.c_str(), AES_256_CTR::AES_256_KEYSIZE);
- *filter=new RGWPutObj_BlockEncrypt(s->cct, *cb, aes);
- goto done;
+ BlockCrypt* block_crypt = nullptr;
+ res = s3_prepare_encrypt(s, attrs, &parts, &block_crypt, crypt_http_responses);
+ if (res == 0 && block_crypt != nullptr) {
+ *filter = new RGWPutObj_BlockEncrypt(s->cct, cb, block_crypt);
}
- /* no other encryption mode, check if default encryption is selected */
- if (s->cct->_conf->rgw_crypt_default_encryption_key != "") {
- std::string master_encryption_key = from_base64(std::string(s->cct->_conf->rgw_crypt_default_encryption_key));
- if (master_encryption_key.size() != 256 / 8) {
- ldout(s->cct, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl;
- /* not an error to return; missing encryption does not inhibit processing */
- goto done;
- }
-
- set_attr(attrs, RGW_ATTR_CRYPT_MODE, "RGW-AUTO");
- std::string key_selector = create_random_key_selector();
- set_attr(attrs, RGW_ATTR_CRYPT_KEYSEL, key_selector);
-
- uint8_t actual_key[AES_256_KEYSIZE];
- if (AES_256_ECB_encrypt((uint8_t*)master_encryption_key.c_str(), AES_256_KEYSIZE,
- (uint8_t*)key_selector.c_str(),
- actual_key, AES_256_KEYSIZE) != true) {
- res = -EIO;
- goto done;
- }
-
- AES_256_CTR* aes=new AES_256_CTR(s->cct);
- aes->set_key(actual_key, AES_256_KEYSIZE);
- *filter=new RGWPutObj_BlockEncrypt(s->cct, *cb, aes);
- goto done;
- }
-
- done:
return res;
}
if (op_ret)
set_req_state_err(s, op_ret);
dump_errno(s);
+ for (auto &it : crypt_http_responses)
+ dump_header(s, it.first, it.second);
end_header(s, this, "application/xml");
if (op_ret == 0) {
dump_start(s);
int RGWInitMultipart_ObjStore_S3::prepare_encryption(map<string, bufferlist>& attrs)
{
int res = 0;
- if (strcmp(s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", ""), "AES256") == 0)
- {
- std::string key_bin = from_base64(s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", ""));
- if (key_bin.size() != AES_256_CTR::AES_256_KEYSIZE) {
- res = -ERR_INVALID_REQUEST;
- goto done;
- }
- const char* keymd5 = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "");
- std::string keymd5_bin = from_base64(keymd5);
- if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
- res = -ERR_INVALID_DIGEST;
- goto done;
- }
- MD5 key_hash;
- uint8_t key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE];
- key_hash.Update((uint8_t*)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) {
- res = -ERR_INVALID_DIGEST;
- goto done;
- }
-
- set_attr(attrs, RGW_ATTR_CRYPT_MODE, "SSE-C-AES256");
- set_attr(attrs, RGW_ATTR_CRYPT_KEYMD5, keymd5_bin);
-
- goto done;
- }
- if (s->cct->_conf->rgw_crypt_default_encryption_key != "")
- {
- set_attr(attrs, RGW_ATTR_CRYPT_MODE, "RGW-AUTO");
- std::string key_selector = create_random_key_selector();
- set_attr(attrs, RGW_ATTR_CRYPT_KEYSEL, key_selector);
- }
- done:
+ res = s3_prepare_encrypt(s, attrs, nullptr, nullptr, crypt_http_responses);
return res;
}
#include "rgw_keystone.h"
#include "rgw_rest_conn.h"
#include "rgw_ldap.h"
+#include "rgw_rest.h"
#include "rgw_token.h"
#include "include/assert.h"
// Serving a custom error page from an object is really a 200 response with
// just the status line altered.
int custom_http_ret = 0;
+ std::map<std::string, std::string> crypt_http_responses;
public:
RGWGetObj_ObjStore_S3() {}
~RGWGetObj_ObjStore_S3() override {}
};
class RGWPutObj_ObjStore_S3 : public RGWPutObj_ObjStore {
+private:
+ std::map<std::string, std::string> crypt_http_responses;
+
public:
RGWPutObj_ObjStore_S3() {}
~RGWPutObj_ObjStore_S3() override {}
RGWPolicyEnv env;
RGWPolicy post_policy;
string err_msg;
+ map<string, string> crypt_http_responses;
const rgw::auth::StrategyRegistry* auth_registry_ptr = nullptr;
};
class RGWInitMultipart_ObjStore_S3 : public RGWInitMultipart_ObjStore {
+private:
+ std::map<std::string, std::string> crypt_http_responses;
public:
RGWInitMultipart_ObjStore_S3() {}
~RGWInitMultipart_ObjStore_S3() override {}