]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
Added aws:kms mode to get/put/post operations.
authorAdam Kupczyk <akupczyk@mirantis.com>
Fri, 10 Jun 2016 14:05:00 +0000 (16:05 +0200)
committerAdam Kupczyk <akupczyk@mirantis.com>
Wed, 5 Apr 2017 16:31:17 +0000 (18:31 +0200)
Refactored to export selection of encryption to rgw/rgw_crypt.h/cc
Added quick exit to from_base64 when string_ref is empty.
Fixed POST logic, so aws encryption can also be applied to objects created from web forms
Extended KeystoneService with barbican user configuration.
Keystone provides token, Barbican provides secret.
Added option rgw_barbican_url.

Signed-off-by: Adam Kupczyk <akupczyk@mirantis.com>
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
src/common/config_opts.h
src/rgw/rgw_b64.h
src/rgw/rgw_crypt.cc
src/rgw/rgw_crypt.h
src/rgw/rgw_json_enc.cc
src/rgw/rgw_keystone.cc
src/rgw/rgw_keystone.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h

index 230ec6c8f7b62a899a5af59651023527d769a093..687474e803f7532fd5234bce8e92ec7ae4f18d7c 100644 (file)
@@ -1460,6 +1460,11 @@ OPTION(rgw_keystone_admin_password, OPT_STR, "")  // keystone admin user passwor
 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
@@ -1472,6 +1477,7 @@ OPTION(rgw_healthcheck_disabling_path, OPT_STR, "") // path that existence cause
 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 */
index 52374f49363518bc2a3d352b80009f3ca6c01a22..3f79eccd0ee2e4cc4c09bc3b33bd7ad63027e4a8 100644 (file)
@@ -61,7 +61,8 @@ namespace rgw {
   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
index c7a7af9d67774969a983b303676efc6e1ca4157f..2136e854f548ef8b885e320ef1ca6b5734fb8cd8 100644 (file)
@@ -8,10 +8,17 @@
 #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;
@@ -393,11 +400,450 @@ int RGWPutObj_BlockEncrypt::throttle_data(void *handle, const rgw_obj& obj,
 }
 
 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;
+}
 
index 07e99e0eabeb6cb736c81c81a793b57062effa3a..8607e73fdb0178532934430a42c58d7712e40245 100644 (file)
@@ -7,6 +7,8 @@
 #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:
@@ -80,7 +82,7 @@ class RGWGetObj_BlockDecrypt : public RGWGetObj_Filter {
   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;
@@ -98,14 +100,25 @@ class RGWPutObj_BlockEncrypt : public RGWPutObj_Filter
   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
index e3f39231b165765b77952426602fcb0fc602aa23..067ad6fadbbbbf63330c9d982f5e80c40baf1e6a 100644 (file)
@@ -1376,6 +1376,53 @@ void rgw::keystone::AdminTokenRequestVer3::dump(Formatter* const f) const
 }
 
 
+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");
index 11583572d2291aac54c503c3e05254ed953fad16..9ea60c7afd4ed89df85a80b82714884583f125e8 100644 (file)
@@ -259,6 +259,81 @@ int Service::issue_admin_token_request(CephContext* const cct,
   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
 {
@@ -368,6 +443,13 @@ bool TokenCache::find_admin(rgw::keystone::TokenEnvelope& token)
   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)
 {
@@ -407,6 +489,14 @@ void TokenCache::add_admin(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);
index 91cf9b13c44866cebd4309789cb47412142d32b7..be354d054632d14e274b9233f40b6504cd8cb796 100644 (file)
@@ -133,6 +133,8 @@ public:
   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);
 };
 
 
@@ -243,6 +245,7 @@ class TokenCache {
   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;
 
@@ -289,8 +292,10 @@ public:
     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:
@@ -326,6 +331,27 @@ public:
   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 */
 
index 4b93da5a5045da2579edafe2683a33c8ad0a73d1..ec147c303370cc5d6de5d52d681c2f097d7db9ce 100644 (file)
@@ -229,6 +229,9 @@ int RGWGetObj_ObjStore_S3::send_response_data(bufferlist& bl, off_t bl_ofs,
     }
   }
 
+  for (auto &it : crypt_http_responses)
+    dump_header(s, it.first, it.second);
+
   dump_content_length(s, total_len);
   dump_last_modified(s, lastmod);
 
@@ -314,143 +317,22 @@ send_data:
 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;
 }
 
@@ -1474,22 +1356,6 @@ static int get_success_retcode(int code)
   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) {
@@ -1562,8 +1428,6 @@ static inline void set_attr(map<string, bufferlist>& attrs, const char* key, con
 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;
@@ -1577,151 +1441,23 @@ int RGWPutObj_ObjStore_S3::get_encrypt_filter(RGWPutObjDataProcessor** filter, R
       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;
 }
 /*
@@ -2389,6 +2125,8 @@ void RGWPostObj_ObjStore_S3::send_response()
 
 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",
@@ -2416,72 +2154,11 @@ done:
 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;
 }
 
@@ -2991,6 +2668,8 @@ void RGWInitMultipart_ObjStore_S3::send_response()
   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);
@@ -3008,41 +2687,7 @@ void RGWInitMultipart_ObjStore_S3::send_response()
 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;
 }
 
index 716f811f9519b76bfd3a4dd13cef4a286c83ea0e..8ac0a1d2bb417b9468861e2bf677dcd34f30f862 100644 (file)
@@ -17,6 +17,7 @@
 #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"
@@ -34,6 +35,7 @@ protected:
   // 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 {}
@@ -165,6 +167,9 @@ public:
 };
 
 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 {}
@@ -203,6 +208,7 @@ class RGWPostObj_ObjStore_S3 : public RGWPostObj_ObjStore {
   RGWPolicyEnv env;
   RGWPolicy post_policy;
   string err_msg;
+  map<string, string> crypt_http_responses;
 
   const rgw::auth::StrategyRegistry* auth_registry_ptr = nullptr;
 
@@ -356,6 +362,8 @@ public:
 };
 
 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 {}