From abcf87dc52ad46a23bd4b2bca56a0af807bcf770 Mon Sep 17 00:00:00 2001 From: Marcus Watts Date: Mon, 7 Dec 2020 17:55:22 -0500 Subject: [PATCH] rgw/kms/vault - encryption context - first part 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 --- src/rgw/rgw_crypt.cc | 341 +++++++++++++++++++++++++++++++++++++++---- src/rgw/rgw_kms.cc | 138 +++++++++++++---- src/rgw/rgw_kms.h | 11 +- 3 files changed, 432 insertions(+), 58 deletions(-) diff --git a/src/rgw/rgw_crypt.cc b/src/rgw/rgw_crypt.cc index 176a830430e09..df0111afebbcd 100644 --- a/src/rgw/rgw_crypt.cc +++ b/src/rgw/rgw_crypt.cc @@ -16,6 +16,11 @@ #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 // libicu #include @@ -25,6 +30,266 @@ using namespace rgw; +template +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 +bool +canonical_char_sorter::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 +bool +canonical_char_sorter::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::MemoryPoolAllocator<> > +MyMember; + +template +bool +sort_and_write(rapidjson::Value &d, H &writer, canonical_char_sorter& ccs) +{ + bool r; + switch(d.GetType()) { + case rapidjson::kObjectType: { + struct comparer { + canonical_char_sorter &r; + comparer(canonical_char_sorter &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 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& 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(f) & static_cast(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 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(isw); + else + d.ParseStream(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 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& 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& 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(new AES_256_CBC(s->cct)); aes->set_key(reinterpret_cast(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 +*********************************************************************/ diff --git a/src/rgw/rgw_kms.cc b/src/rgw/rgw_kms.cc index 2da5ce4789007..260ff091b925e 100644 --- a/src/rgw/rgw_kms.cc +++ b/src/rgw/rgw_kms.cc @@ -37,6 +37,7 @@ static void concat_url(std::string &url, std::string path) { } } +typedef std::map 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 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& 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& 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& 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& 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& 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); +} diff --git a/src/rgw/rgw_kms.h b/src/rgw/rgw_kms.h index 89b58ba1c5e90..e06b8038b173a 100644 --- a/src/rgw/rgw_kms.h +++ b/src/rgw/rgw_kms.h @@ -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& attrs, + std::string& actual_key); +int reconstitute_actual_key_from_kms(CephContext *cct, + map& 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 -- 2.39.5