]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/kms/vault - encryption context - first part
authorMarcus Watts <mwatts@redhat.com>
Mon, 7 Dec 2020 22:55:22 +0000 (17:55 -0500)
committerMarcus Watts <mwatts@redhat.com>
Sat, 6 Mar 2021 04:05:13 +0000 (23:05 -0500)
This includes the logic to process the user provided
encryption context, turn it into "canonical json", and
to add in a default arn if it's not present.

Also present here is the start of logic to distinguish
between "prepare_encrypt" and "prepare_decrypt" at a lower
level; as "make_key" and "reconstitute_key" these will be
the functions that separately create a new datakey using
the vault transit operation, and to retrieve a previously
stored datakey.

Fixes: http://tracker.ceph.com/issues/48746
Signed-off-by: Marcus Watts <mwatts@redhat.com>
src/rgw/rgw_crypt.cc
src/rgw/rgw_kms.cc
src/rgw/rgw_kms.h

index 176a830430e0909219e91c32f54d8147bbd7c755..df0111afebbcd3d61894eac4ba0d17cb646d9de7 100644 (file)
 #include "crypto/crypto_accel.h"
 #include "crypto/crypto_plugin.h"
 #include "rgw/rgw_kms.h"
+#include "rapidjson/document.h"
+#include "rapidjson/writer.h"
+#include "rapidjson/error/error.h"
+#include "rapidjson/error/en.h"
+#include <unicode/normalizer2.h>       // libicu
 
 #include <openssl/evp.h>
 
 using namespace rgw;
 
 
+template<typename M>
+class canonical_char_sorter {
+private:
+    const icu::Normalizer2* normalizer;
+    CephContext *cct;
+
+public:
+    canonical_char_sorter(CephContext *cct) : cct(cct) {
+        UErrorCode status = U_ZERO_ERROR;
+        normalizer = icu::Normalizer2::getNFCInstance(status);
+        if (U_FAILURE(status)) {
+lderr(cct) << "ERROR: can't get nfc instance, error = " << status << dendl;
+            normalizer = 0;
+        }
+    }
+    bool compare_helper (const M *, const M *);
+    bool make_string_canonical(rapidjson::Value &,
+        rapidjson::Document::AllocatorType&);
+};
+
+template<typename M>
+bool
+canonical_char_sorter<M>::compare_helper (const M*a, const M*b)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    const std::string as{a->name.GetString(), a->name.GetStringLength()},
+        bs{b->name.GetString(), b->name.GetStringLength()};
+    icu::UnicodeString aw{icu::UnicodeString::fromUTF8(as)}, bw{icu::UnicodeString::fromUTF8(bs)};
+    int32_t afl{ aw.countChar32()}, bfl{bw.countChar32()};
+    std::u32string af, bf;
+    af.resize(afl); bf.resize(bfl);
+    auto *astr{af.c_str()}, *bstr{bf.c_str()};
+    aw.toUTF32((int32_t*)astr, afl, status);
+    bw.toUTF32((int32_t*)bstr, bfl, status);
+    bool r{af < bf};
+    return r;
+}
+
+template<typename M>
+bool
+canonical_char_sorter<M>::make_string_canonical (rapidjson::Value &v, rapidjson::Document::AllocatorType&a)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    const std::string as{v.GetString(), v.GetStringLength()};
+
+    if (!normalizer)
+        return false;
+    const icu::UnicodeString aw{icu::UnicodeString::fromUTF8(as)};
+    icu::UnicodeString an{normalizer->normalize(aw, status)};
+    if (U_FAILURE(status)) {
+        ldout(cct, 5) << "conversion error; code=" << status <<
+            " on string " << as << dendl;
+        return false;
+    }
+    std::string ans;
+    an.toUTF8String(ans);
+    v.SetString(ans.c_str(), ans.length(), a);
+    return true;
+}
+
+typedef
+rapidjson::GenericMember<rapidjson::UTF8<>, rapidjson::MemoryPoolAllocator<> >
+MyMember;
+
+template<typename H>
+bool
+sort_and_write(rapidjson::Value &d, H &writer, canonical_char_sorter<MyMember>& ccs)
+{
+    bool r;
+    switch(d.GetType()) {
+    case rapidjson::kObjectType: {
+    struct comparer {
+        canonical_char_sorter<MyMember> &r;
+        comparer(canonical_char_sorter<MyMember> &r) : r(r) {};
+        bool operator()(const MyMember*a, const MyMember*b) {
+            return r.compare_helper(a,b);
+        }
+    } cmp_functor{ccs};
+        if (!(r = writer.StartObject()))
+            break;
+        const auto &o{d.GetObject()};
+        auto b{o.begin()},e{o.end()};
+        std::vector<MyMember*> q;
+        for (auto &m: d.GetObject())
+            q.push_back(&m);
+        std::sort(q.begin(), q.end(), cmp_functor);
+        for (auto m: q) {
+            assert(m->name.IsString());
+            if (!(r = writer.Key(m->name.GetString(), m->name.GetStringLength())))
+                goto Done;
+            if (!(r = sort_and_write(m->value, writer, ccs)))
+                goto Done;
+        }
+        r = writer.EndObject();
+        break; }
+    case rapidjson::kArrayType:
+        if (!(r = writer.StartArray()))
+            break;
+        for (auto &v: d.GetArray()) {
+            if (!(r = sort_and_write(v, writer, ccs)))
+                goto Done;
+        }
+        r = writer.EndArray();
+        break;
+    default:
+        r = d.Accept(writer);
+        break;
+    }
+Done:
+    return r;
+}
+
+enum struct mec_option {
+empty = 0, number_ok = 1
+};
+
+enum struct mec_error {
+success = 0, conversion, number
+};
+
+mec_error
+make_everything_canonical(rapidjson::Value &d, rapidjson::Document::AllocatorType&a, canonical_char_sorter<MyMember>& ccs, mec_option f = mec_option::empty )
+{
+    mec_error r;
+    switch(d.GetType()) {
+    case rapidjson::kObjectType:
+        for (auto &m: d.GetObject()) {
+            assert(m.name.IsString());
+            if (!ccs.make_string_canonical(m.name, a)) {
+                r = mec_error::conversion;
+                goto Error;
+            }
+            if ((r = make_everything_canonical(m.value, a, ccs, f)) != mec_error::success)
+                goto Error;
+        }
+        break;
+    case rapidjson::kArrayType:
+        for (auto &v: d.GetArray()) {
+            if ((r = make_everything_canonical(v, a, ccs, f)) != mec_error::success)
+                goto Error;
+        }
+        break;
+    case rapidjson::kStringType:
+        if (!ccs.make_string_canonical(d, a)) {
+            r = mec_error::conversion;
+            goto Error;
+        }
+        break;
+    case rapidjson::kNumberType:
+        if (static_cast<int>(f) & static_cast<int>(mec_option::number_ok))
+            break;
+        r = mec_error::number;
+        goto Error;
+    default:
+        break;
+    }
+    r = mec_error::success;
+Error:
+    return r;
+}
+
+bool
+add_object_to_context(rgw_obj &obj, rapidjson::Document &d)
+{
+    ARN a{obj};
+    const char aws_s3_arn[] { "aws:s3:arn" };
+    std::string as{a.to_string()};
+    rapidjson::Document::AllocatorType &allocator { d.GetAllocator() };
+    rapidjson::Value name, val;
+
+    if (!d.IsObject())
+        return false;
+    if (d.HasMember(aws_s3_arn))
+        return true;
+    val.SetString(as.c_str(), as.length(), allocator);
+    name.SetString(aws_s3_arn, sizeof aws_s3_arn - 1, allocator);
+    d.AddMember(name, val, allocator);
+    return true;
+}
+
+static inline const std::string &
+get_tenant_or_id(req_state *s)
+{
+    const std::string &tenant{ s->user->get_tenant() };
+    if (!tenant.empty()) return tenant;
+    return s->user->get_id().id;
+}
+
+int
+make_canonical_context(struct req_state *s,
+    std::string_view &context,
+    std::string &cooked_context)
+{
+    rapidjson::Document d;
+    bool b = false;
+mec_option options {
+//mec_option::number_ok :      SEE BOTTOM OF FILE
+mec_option::empty };
+    rgw_obj obj;
+    std::ostringstream oss;
+    canonical_char_sorter<MyMember> ccs{s->cct};
+
+    obj.bucket.tenant = get_tenant_or_id(s);
+    obj.bucket.name = s->bucket->get_name();
+    obj.key.name = s->object->get_name();
+    std::string iline;
+    rapidjson::Document::AllocatorType &allocator { d.GetAllocator() };
+
+    try {
+       iline = rgw::from_base64(context);
+    } catch (const std::exception& e) {
+       oss << "bad context: " << e.what();
+       s->err.message = oss.str();
+        return -ERR_INVALID_REQUEST;
+    }
+    rapidjson::StringStream isw(iline.c_str());
+    if (!iline.length())
+        d.SetObject();
+//    else if (qflag)          SEE BOTTOM OF FILE
+//       d.ParseStream<rapidjson::kParseNumbersAsStringsFlag>(isw);
+    else
+        d.ParseStream<rapidjson::kParseFullPrecisionFlag>(isw);
+    if (isw.Tell() != iline.length()) {
+        oss << "bad context: did not consume all of input: @ "
+           << isw.Tell();
+       s->err.message = oss.str();
+        return -ERR_INVALID_REQUEST;
+    }
+    if (d.HasParseError()) {
+        oss << "bad context: parse error: @ " << d.GetErrorOffset()
+           << " " << rapidjson::GetParseError_En(d.GetParseError());
+       s->err.message = oss.str();
+        return -ERR_INVALID_REQUEST;
+    }
+    rapidjson::StringBuffer buf;
+    rapidjson::Writer<rapidjson::StringBuffer> writer(buf);
+    if (!add_object_to_context(obj, d)) {
+       lderr(s->cct) << "ERROR: can't add default value to context" << dendl;
+       s->err.message = "context: internal error adding defaults";
+        return -ERR_INVALID_REQUEST;
+    }
+    b = make_everything_canonical(d, allocator, ccs, options) == mec_error::success;
+    if (!b) {
+       lderr(s->cct) << "ERROR: can't make canonical json <"
+           << context << ">" << dendl;
+       s->err.message = "context: can't make canonical";
+        return -ERR_INVALID_REQUEST;
+    }
+    b = sort_and_write(d, writer, ccs);
+    if (!b) {
+       ldout(s->cct, 5) << "format error <" << context
+           << ">: partial.results=" << buf.GetString() << dendl;
+       s->err.message = "unable to reformat json";
+        return -ERR_INVALID_REQUEST;
+    }
+    cooked_context = rgw::to_base64(buf.GetString());
+    return 0;
+}
+
+
 CryptoAccelRef get_crypto_accel(CephContext *cct)
 {
   CryptoAccelRef ca_impl = nullptr;
@@ -578,31 +843,13 @@ std::string create_random_key_selector(CephContext * const cct) {
   return std::string(random, sizeof(random));
 }
 
-static inline void set_attr(map<string, bufferlist>& attrs,
-                            const char* key,
-                            std::string_view value)
-{
-  bufferlist bl;
-  bl.append(value.data(), value.size());
-  attrs[key] = std::move(bl);
-}
-
-static inline std::string get_str_attribute(map<string, bufferlist>& attrs,
-                                            const char *name)
-{
-  auto iter = attrs.find(name);
-  if (iter == attrs.end()) {
-    return {};
-  }
-  return iter->second.to_str();
-}
-
 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_CONTEXT,
   X_AMZ_SERVER_SIDE_ENCRYPTION_LAST
 } crypt_option_e;
 
@@ -617,6 +864,7 @@ static const crypt_option_names crypt_options[] = {
     {"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"},
+    {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CONTEXT",             "x-amz-server-side-encryption-context"},
 };
 
 static std::string_view get_crypt_attribute(
@@ -776,6 +1024,11 @@ int rgw_s3_prepare_encrypt(struct req_state* s,
       }
 
       if (req_sse == "aws:kms") {
+       std::string_view context =
+          get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CONTEXT);
+        std::string cooked_context;
+       if ((res = make_canonical_context(s, context, cooked_context)))
+         return res;
        std::string_view key_id =
           get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID);
        if (key_id.empty()) {
@@ -786,8 +1039,12 @@ int rgw_s3_prepare_encrypt(struct req_state* s,
        }
        /* try to retrieve actual key */
        std::string key_selector = create_random_key_selector(s->cct);
+       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);
+       set_attr(attrs, RGW_ATTR_CRYPT_CONTEXT, cooked_context);
        std::string actual_key;
-       res = get_actual_key_from_kms(s->cct, key_id, key_selector, actual_key);
+       res = make_actual_key_from_kms(s->cct, attrs, actual_key);
        if (res != 0) {
          ldout(s->cct, 5) << "ERROR: failed to retrieve actual key from key_id: " << key_id << dendl;
          s->err.message = "Failed to retrieve the actual key, kms-keyid: " + std::string(key_id);
@@ -799,19 +1056,17 @@ int rgw_s3_prepare_encrypt(struct req_state* s,
          s->err.message = "KMS provided an invalid key for the given kms-keyid.";
          return -ERR_INVALID_ACCESS_KEY;
        }
-       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) {
          auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
          aes->set_key(reinterpret_cast<const uint8_t*>(actual_key.c_str()), AES_256_KEYSIZE);
          *block_crypt = std::move(aes);
        }
-       actual_key.replace(0, actual_key.length(), actual_key.length(), '\000');
+        ::ceph::crypto::zeroize_for_security(actual_key.data(), actual_key.length());
 
        crypt_http_responses["x-amz-server-side-encryption"] = "aws:kms";
        crypt_http_responses["x-amz-server-side-encryption-aws-kms-key-id"] = std::string(key_id);
+       crypt_http_responses["x-amz-server-side-encryption-context"] = std::move(cooked_context);
        return 0;
       } else if (req_sse == "AES256") {
        /* if a default encryption key was provided, we will use it for SSE-S3 */
@@ -987,9 +1242,8 @@ int rgw_s3_prepare_decrypt(struct req_state* s,
     }
     /* 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);
+    res = reconstitute_actual_key_from_kms(s->cct, attrs, actual_key);
     if (res != 0) {
       ldout(s->cct, 10) << "ERROR: failed to retrieve actual key from key_id: " << key_id << dendl;
       s->err.message = "Failed to retrieve the actual key, kms-keyid: " + key_id;
@@ -1051,3 +1305,38 @@ int rgw_s3_prepare_decrypt(struct req_state* s,
   /*no decryption*/
   return 0;
 }
+
+/*********************************************************************
+*      "BOTTOM OF FILE"
+*      I've left some commented out lines above.  They are there for
+*      a reason, which I will explain.  The "canonical" json constructed
+*      by the code above as a crypto context must take a json object and
+*      turn it into a unique determinstic fixed form.  For most json
+*      types this is easy.  The hardest problem that is handled above is
+*      detailing with unicode strings; they must be turned into
+*      NFC form and sorted in a fixed order.  Numbers, however,
+*      are another story.  Json makes no distinction between integers
+*      and floating point, and both types have their problems.
+*      Integers can overflow, so very large numbers are a problem.
+*      Floating point is even worse; not all floating point numbers
+*      can be represented accurately in c++ data types, and there
+*      are many quirks regarding how overflow, underflow, and loss
+*      of significance are handled.
+*
+*      In this version of the code, I took the simplest answer, I
+*      reject all numbers altogether.  This is not ideal, but it's
+*      the only choice that is guaranteed to be future compatible.
+*      AWS S3 does not guarantee to support numbers at all; but it
+*      actually converts all numbers into strings right off.
+*      This has the interesting property that 7 and 007 are different,
+*      but that 007 and "007" are the same.  I would rather
+*      treat numbers as a string of digits and have logic
+*      to produce the "most compact" equivalent form.  This can
+*      fix all the overflow/underflow problems, but it requires
+*      fixing the json parser part, and I put that problem off.
+*
+*      The commented code above indicates places in this code that
+*      will need to be revised depending on future work in this area.
+*      Removing those comments makes that work harder.
+*                              February 25, 2021
+*********************************************************************/
index 2da5ce47890074df9bcd61d44d872d3a0d82084e..260ff091b925ec56a037887ab989a308ab170df7 100644 (file)
@@ -37,6 +37,7 @@ static void concat_url(std::string &url, std::string path) {
   }
 }
 
+typedef std::map<std::string, std::string> EngineParmMap;
 
 class VaultSecretEngine: public SecretEngine {
 
@@ -86,7 +87,7 @@ protected:
     return res;
   }
 
-  int send_request(std::string_view key_id, JSONParser* parser) override
+  int send_request(std::string_view key_id, JSONParser* parser)
   {
     bufferlist secret_bl;
     int res;
@@ -167,13 +168,15 @@ public:
     this->cct = cct;
   }
 
-  virtual ~VaultSecretEngine(){}
+//  virtual ~VaultSecretEngine(){}
 };
 
 
 class TransitSecretEngine: public VaultSecretEngine {
 
 private:
+  EngineParmMap parms;
+
   int get_key_version(std::string_view key_id, string& version)
   {
     size_t pos = 0;
@@ -190,7 +193,12 @@ private:
   }
 
 public:
-  TransitSecretEngine(CephContext *cct): VaultSecretEngine(cct){ }
+  TransitSecretEngine(CephContext *cct, EngineParmMap parms): VaultSecretEngine(cct), parms(parms) {
+    for (auto& e: parms) {
+      lderr(cct) << "ERROR: vault transit secrets engine : parameter "
+       << e.first << "=" << e.second << " ignored" << dendl;
+    }
+  }
 
   int get_key(std::string_view key_id, std::string& actual_key)
   {
@@ -226,7 +234,11 @@ class KvSecretEngine: public VaultSecretEngine {
 
 public:
 
-  KvSecretEngine(CephContext *cct): VaultSecretEngine(cct){ }
+  KvSecretEngine(CephContext *cct, EngineParmMap parms): VaultSecretEngine(cct){
+    if (!parms.empty()) {
+      lderr(cct) << "ERROR: vault kv secrets engine takes no parameters (ignoring them)" << dendl;
+    }
+  }
 
   virtual ~KvSecretEngine(){}
 
@@ -333,14 +345,14 @@ class KmipSecretEngine: public SecretEngine {
 protected:
   CephContext *cct;
 
-  int send_request(std::string_view key_id, JSONParser* parser) override
-  {
-    return -EINVAL;
-  }
-
-  int decode_secret(JSONObj* json_obj, std::string& actual_key){
-    return -EINVAL;
-  }
+//  int send_request(std::string_view key_id, JSONParser* parser) override
+//  {
+//    return -EINVAL;
+//  }
+//
+//  int decode_secret(JSONObj* json_obj, std::string& actual_key){
+//    return -EINVAL;
+//  }
 
 public:
 
@@ -469,20 +481,64 @@ static int get_actual_key_from_barbican(CephContext *cct,
 }
 
 
+std::string config_to_engine_and_parms(CephContext *cct,
+    const char* which,
+    std::string& secret_engine_str,
+    EngineParmMap& secret_engine_parms)
+{
+  std::ostringstream oss;
+  std::vector<std::string> secret_engine_v;
+  std::string secret_engine;
+
+  get_str_vec(secret_engine_str, " ", secret_engine_v);
+
+  cct->_conf.early_expand_meta(secret_engine_str, &oss);
+  auto meta_errors {oss.str()};
+  if (meta_errors.length()) {
+    meta_errors.erase(meta_errors.find_last_not_of("\n")+1);
+    lderr(cct) << "ERROR: while expanding " << which << ": "
+       << meta_errors << dendl;
+  }
+  for (auto& e: secret_engine_v) {
+    if (!secret_engine.length()) {
+      secret_engine = std::move(e);
+      continue;
+    }
+    auto p { e.find('=') };
+    if (p == std::string::npos) {
+      secret_engine_parms.emplace(std::move(e), "");
+      continue;
+    }
+    std::string key{ e.substr(0,p) };
+    std::string val{ e.substr(p+1) };
+    secret_engine_parms.emplace(std::move(key), std::move(val));
+  }
+  return secret_engine;
+}
+
+
 static int get_actual_key_from_vault(CephContext *cct,
-                                     std::string_view key_id,
+                                     map<string, bufferlist>& attrs,
                                      std::string& actual_key)
 {
-  std::string secret_engine = cct->_conf->rgw_crypt_vault_secret_engine;
+  std::string secret_engine_str = cct->_conf->rgw_crypt_vault_secret_engine;
+  std::string context = get_str_attribute(attrs, RGW_ATTR_CRYPT_CONTEXT);
+  EngineParmMap secret_engine_parms;
+  auto secret_engine { config_to_engine_and_parms(
+    cct, "rgw_crypt_vault_secret_engine",
+    secret_engine_str, secret_engine_parms) };
   ldout(cct, 20) << "Vault authentication method: " << cct->_conf->rgw_crypt_vault_auth << dendl;
   ldout(cct, 20) << "Vault Secrets Engine: " << secret_engine << dendl;
+lderr(cct) << "TEMP cooked_context<" << context << ">" << dendl;
 
   if (RGW_SSE_KMS_VAULT_SE_KV == secret_engine){
-    KvSecretEngine engine(cct);
+    std::string key_id = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYID);
+    KvSecretEngine engine(cct, std::move(secret_engine_parms));
     return engine.get_key(key_id, actual_key);
   }
   else if (RGW_SSE_KMS_VAULT_SE_TRANSIT == secret_engine){
-    TransitSecretEngine engine(cct);
+    std::string key_id = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYID);
+    TransitSecretEngine engine(cct, std::move(secret_engine_parms));
     return engine.get_key(key_id, actual_key);
   }
   else{
@@ -492,6 +548,22 @@ static int get_actual_key_from_vault(CephContext *cct,
 }
 
 
+static int make_actual_key_from_vault(CephContext *cct,
+                                     map<string, bufferlist>& attrs,
+                                     std::string& actual_key)
+{
+    return get_actual_key_from_vault(cct, attrs, actual_key);
+}
+
+
+static int reconstitute_actual_key_from_vault(CephContext *cct,
+                                     map<string, bufferlist>& attrs,
+                                     std::string& actual_key)
+{
+    return get_actual_key_from_vault(cct, attrs, actual_key);
+}
+
+
 static int get_actual_key_from_kmip(CephContext *cct,
                                      std::string_view key_id,
                                      std::string& actual_key)
@@ -509,29 +581,43 @@ static int get_actual_key_from_kmip(CephContext *cct,
 }
 
 
-int get_actual_key_from_kms(CephContext *cct,
-                            std::string_view key_id,
-                            std::string_view key_selector,
+int reconstitute_actual_key_from_kms(CephContext *cct,
+                            map<string, bufferlist>& attrs,
                             std::string& actual_key)
 {
-  std::string kms_backend;
+  std::string key_id = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYID);
+  std::string kms_backend { cct->_conf->rgw_crypt_s3_kms_backend };
 
-  kms_backend = cct->_conf->rgw_crypt_s3_kms_backend;
   ldout(cct, 20) << "Getting KMS encryption key for key " << key_id << dendl;
   ldout(cct, 20) << "SSE-KMS backend is " << kms_backend << dendl;
 
-  if (RGW_SSE_KMS_BACKEND_BARBICAN == kms_backend)
+  if (RGW_SSE_KMS_BACKEND_BARBICAN == kms_backend) {
     return get_actual_key_from_barbican(cct, key_id, actual_key);
+  }
 
-  if (RGW_SSE_KMS_BACKEND_VAULT == kms_backend)
-    return get_actual_key_from_vault(cct, key_id, actual_key);
+  if (RGW_SSE_KMS_BACKEND_VAULT == kms_backend) {
+    return reconstitute_actual_key_from_vault(cct, attrs, actual_key);
+  }
 
-  if (RGW_SSE_KMS_BACKEND_KMIP == kms_backend)
+  if (RGW_SSE_KMS_BACKEND_KMIP == kms_backend) {
     return get_actual_key_from_kmip(cct, key_id, actual_key);
+  }
 
-  if (RGW_SSE_KMS_BACKEND_TESTING == kms_backend)
+  if (RGW_SSE_KMS_BACKEND_TESTING == kms_backend) {
+    std::string key_selector = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYSEL);
     return get_actual_key_from_conf(cct, key_id, key_selector, actual_key);
+  }
 
   ldout(cct, 0) << "ERROR: Invalid rgw_crypt_s3_kms_backend: " << kms_backend << dendl;
   return -EINVAL;
 }
+
+int make_actual_key_from_kms(CephContext *cct,
+                            map<string, bufferlist>& attrs,
+                            std::string& actual_key)
+{
+  std::string kms_backend { cct->_conf->rgw_crypt_s3_kms_backend };
+  if (RGW_SSE_KMS_BACKEND_VAULT == kms_backend)
+    return make_actual_key_from_vault(cct, attrs, actual_key);
+  return reconstitute_actual_key_from_kms(cct, attrs, actual_key);
+}
index 89b58ba1c5e909a9011c80d01840103c75f709d7..e06b8038b173a10e8e5a5ece53210eede9dbf024 100644 (file)
@@ -31,9 +31,11 @@ static const std::string RGW_SSE_KMS_KMIP_SE_KV = "kv";
  * TODO
  * \return
  */
-int get_actual_key_from_kms(CephContext *cct,
-                            std::string_view key_id,
-                            std::string_view key_selector,
+int make_actual_key_from_kms(CephContext *cct,
+                            map<string, bufferlist>& attrs,
+                            std::string& actual_key);
+int reconstitute_actual_key_from_kms(CephContext *cct,
+                            map<string, bufferlist>& attrs,
                             std::string& actual_key);
 
 /**
@@ -46,8 +48,5 @@ class SecretEngine {
 public:
   virtual int get_key(std::string_view key_id, std::string& actual_key) = 0;
   virtual ~SecretEngine(){};
-protected:
-  virtual int send_request(std::string_view key_id, JSONParser* parser) = 0;
-  virtual int decode_secret(JSONObj* json_obj, std::string& actual_key) = 0;
 };
 #endif