]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_crypt.cc
import ceph pacific 16.2.5
[ceph.git] / ceph / src / rgw / rgw_crypt.cc
1 // -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
3
4 /**
5 * Crypto filters for Put/Post/Get operations.
6 */
7
8 #include <string_view>
9
10 #include <rgw/rgw_op.h>
11 #include <rgw/rgw_crypt.h>
12 #include <auth/Crypto.h>
13 #include <rgw/rgw_b64.h>
14 #include <rgw/rgw_rest_s3.h>
15 #include "include/ceph_assert.h"
16 #include "crypto/crypto_accel.h"
17 #include "crypto/crypto_plugin.h"
18 #include "rgw/rgw_kms.h"
19 #include "rapidjson/document.h"
20 #include "rapidjson/writer.h"
21 #include "rapidjson/error/error.h"
22 #include "rapidjson/error/en.h"
23 #include <unicode/normalizer2.h> // libicu
24
25 #include <openssl/evp.h>
26
27 #define dout_context g_ceph_context
28 #define dout_subsys ceph_subsys_rgw
29
30 using namespace rgw;
31
32
33 template<typename M>
34 class canonical_char_sorter {
35 private:
36 const icu::Normalizer2* normalizer;
37 CephContext *cct;
38
39 public:
40 canonical_char_sorter(CephContext *cct) : cct(cct) {
41 UErrorCode status = U_ZERO_ERROR;
42 normalizer = icu::Normalizer2::getNFCInstance(status);
43 if (U_FAILURE(status)) {
44 lderr(cct) << "ERROR: can't get nfc instance, error = " << status << dendl;
45 normalizer = 0;
46 }
47 }
48 bool compare_helper (const M *, const M *);
49 bool make_string_canonical(rapidjson::Value &,
50 rapidjson::Document::AllocatorType&);
51 };
52
53 template<typename M>
54 bool
55 canonical_char_sorter<M>::compare_helper (const M*a, const M*b)
56 {
57 UErrorCode status = U_ZERO_ERROR;
58 const std::string as{a->name.GetString(), a->name.GetStringLength()},
59 bs{b->name.GetString(), b->name.GetStringLength()};
60 icu::UnicodeString aw{icu::UnicodeString::fromUTF8(as)}, bw{icu::UnicodeString::fromUTF8(bs)};
61 int32_t afl{ aw.countChar32()}, bfl{bw.countChar32()};
62 std::u32string af, bf;
63 af.resize(afl); bf.resize(bfl);
64 auto *astr{af.c_str()}, *bstr{bf.c_str()};
65 aw.toUTF32((int32_t*)astr, afl, status);
66 bw.toUTF32((int32_t*)bstr, bfl, status);
67 bool r{af < bf};
68 return r;
69 }
70
71 template<typename M>
72 bool
73 canonical_char_sorter<M>::make_string_canonical (rapidjson::Value &v, rapidjson::Document::AllocatorType&a)
74 {
75 UErrorCode status = U_ZERO_ERROR;
76 const std::string as{v.GetString(), v.GetStringLength()};
77
78 if (!normalizer)
79 return false;
80 const icu::UnicodeString aw{icu::UnicodeString::fromUTF8(as)};
81 icu::UnicodeString an{normalizer->normalize(aw, status)};
82 if (U_FAILURE(status)) {
83 ldout(cct, 5) << "conversion error; code=" << status <<
84 " on string " << as << dendl;
85 return false;
86 }
87 std::string ans;
88 an.toUTF8String(ans);
89 v.SetString(ans.c_str(), ans.length(), a);
90 return true;
91 }
92
93 typedef
94 rapidjson::GenericMember<rapidjson::UTF8<>, rapidjson::MemoryPoolAllocator<> >
95 MyMember;
96
97 template<typename H>
98 bool
99 sort_and_write(rapidjson::Value &d, H &writer, canonical_char_sorter<MyMember>& ccs)
100 {
101 bool r;
102 switch(d.GetType()) {
103 case rapidjson::kObjectType: {
104 struct comparer {
105 canonical_char_sorter<MyMember> &r;
106 comparer(canonical_char_sorter<MyMember> &r) : r(r) {};
107 bool operator()(const MyMember*a, const MyMember*b) {
108 return r.compare_helper(a,b);
109 }
110 } cmp_functor{ccs};
111 if (!(r = writer.StartObject()))
112 break;
113 const auto &o{d.GetObject()};
114 auto b{o.begin()},e{o.end()};
115 std::vector<MyMember*> q;
116 for (auto &m: d.GetObject())
117 q.push_back(&m);
118 std::sort(q.begin(), q.end(), cmp_functor);
119 for (auto m: q) {
120 assert(m->name.IsString());
121 if (!(r = writer.Key(m->name.GetString(), m->name.GetStringLength())))
122 goto Done;
123 if (!(r = sort_and_write(m->value, writer, ccs)))
124 goto Done;
125 }
126 r = writer.EndObject();
127 break; }
128 case rapidjson::kArrayType:
129 if (!(r = writer.StartArray()))
130 break;
131 for (auto &v: d.GetArray()) {
132 if (!(r = sort_and_write(v, writer, ccs)))
133 goto Done;
134 }
135 r = writer.EndArray();
136 break;
137 default:
138 r = d.Accept(writer);
139 break;
140 }
141 Done:
142 return r;
143 }
144
145 enum struct mec_option {
146 empty = 0, number_ok = 1
147 };
148
149 enum struct mec_error {
150 success = 0, conversion, number
151 };
152
153 mec_error
154 make_everything_canonical(rapidjson::Value &d, rapidjson::Document::AllocatorType&a, canonical_char_sorter<MyMember>& ccs, mec_option f = mec_option::empty )
155 {
156 mec_error r;
157 switch(d.GetType()) {
158 case rapidjson::kObjectType:
159 for (auto &m: d.GetObject()) {
160 assert(m.name.IsString());
161 if (!ccs.make_string_canonical(m.name, a)) {
162 r = mec_error::conversion;
163 goto Error;
164 }
165 if ((r = make_everything_canonical(m.value, a, ccs, f)) != mec_error::success)
166 goto Error;
167 }
168 break;
169 case rapidjson::kArrayType:
170 for (auto &v: d.GetArray()) {
171 if ((r = make_everything_canonical(v, a, ccs, f)) != mec_error::success)
172 goto Error;
173 }
174 break;
175 case rapidjson::kStringType:
176 if (!ccs.make_string_canonical(d, a)) {
177 r = mec_error::conversion;
178 goto Error;
179 }
180 break;
181 case rapidjson::kNumberType:
182 if (static_cast<int>(f) & static_cast<int>(mec_option::number_ok))
183 break;
184 r = mec_error::number;
185 goto Error;
186 default:
187 break;
188 }
189 r = mec_error::success;
190 Error:
191 return r;
192 }
193
194 bool
195 add_object_to_context(rgw_obj &obj, rapidjson::Document &d)
196 {
197 ARN a{obj};
198 const char aws_s3_arn[] { "aws:s3:arn" };
199 std::string as{a.to_string()};
200 rapidjson::Document::AllocatorType &allocator { d.GetAllocator() };
201 rapidjson::Value name, val;
202
203 if (!d.IsObject())
204 return false;
205 if (d.HasMember(aws_s3_arn))
206 return true;
207 val.SetString(as.c_str(), as.length(), allocator);
208 name.SetString(aws_s3_arn, sizeof aws_s3_arn - 1, allocator);
209 d.AddMember(name, val, allocator);
210 return true;
211 }
212
213 static inline const std::string &
214 get_tenant_or_id(req_state *s)
215 {
216 const std::string &tenant{ s->user->get_tenant() };
217 if (!tenant.empty()) return tenant;
218 return s->user->get_id().id;
219 }
220
221 int
222 make_canonical_context(struct req_state *s,
223 std::string_view &context,
224 std::string &cooked_context)
225 {
226 rapidjson::Document d;
227 bool b = false;
228 mec_option options {
229 //mec_option::number_ok : SEE BOTTOM OF FILE
230 mec_option::empty };
231 rgw_obj obj;
232 std::ostringstream oss;
233 canonical_char_sorter<MyMember> ccs{s->cct};
234
235 obj.bucket.tenant = get_tenant_or_id(s);
236 obj.bucket.name = s->bucket->get_name();
237 obj.key.name = s->object->get_name();
238 std::string iline;
239 rapidjson::Document::AllocatorType &allocator { d.GetAllocator() };
240
241 try {
242 iline = rgw::from_base64(context);
243 } catch (const std::exception& e) {
244 oss << "bad context: " << e.what();
245 s->err.message = oss.str();
246 return -ERR_INVALID_REQUEST;
247 }
248 rapidjson::StringStream isw(iline.c_str());
249 if (!iline.length())
250 d.SetObject();
251 // else if (qflag) SEE BOTTOM OF FILE
252 // d.ParseStream<rapidjson::kParseNumbersAsStringsFlag>(isw);
253 else
254 d.ParseStream<rapidjson::kParseFullPrecisionFlag>(isw);
255 if (isw.Tell() != iline.length()) {
256 oss << "bad context: did not consume all of input: @ "
257 << isw.Tell();
258 s->err.message = oss.str();
259 return -ERR_INVALID_REQUEST;
260 }
261 if (d.HasParseError()) {
262 oss << "bad context: parse error: @ " << d.GetErrorOffset()
263 << " " << rapidjson::GetParseError_En(d.GetParseError());
264 s->err.message = oss.str();
265 return -ERR_INVALID_REQUEST;
266 }
267 rapidjson::StringBuffer buf;
268 rapidjson::Writer<rapidjson::StringBuffer> writer(buf);
269 if (!add_object_to_context(obj, d)) {
270 lderr(s->cct) << "ERROR: can't add default value to context" << dendl;
271 s->err.message = "context: internal error adding defaults";
272 return -ERR_INVALID_REQUEST;
273 }
274 b = make_everything_canonical(d, allocator, ccs, options) == mec_error::success;
275 if (!b) {
276 lderr(s->cct) << "ERROR: can't make canonical json <"
277 << context << ">" << dendl;
278 s->err.message = "context: can't make canonical";
279 return -ERR_INVALID_REQUEST;
280 }
281 b = sort_and_write(d, writer, ccs);
282 if (!b) {
283 ldout(s->cct, 5) << "format error <" << context
284 << ">: partial.results=" << buf.GetString() << dendl;
285 s->err.message = "unable to reformat json";
286 return -ERR_INVALID_REQUEST;
287 }
288 cooked_context = rgw::to_base64(buf.GetString());
289 return 0;
290 }
291
292
293 CryptoAccelRef get_crypto_accel(CephContext *cct)
294 {
295 CryptoAccelRef ca_impl = nullptr;
296 stringstream ss;
297 PluginRegistry *reg = cct->get_plugin_registry();
298 string crypto_accel_type = cct->_conf->plugin_crypto_accelerator;
299
300 CryptoPlugin *factory = dynamic_cast<CryptoPlugin*>(reg->get_with_load("crypto", crypto_accel_type));
301 if (factory == nullptr) {
302 lderr(cct) << __func__ << " cannot load crypto accelerator of type " << crypto_accel_type << dendl;
303 return nullptr;
304 }
305 int err = factory->factory(&ca_impl, &ss);
306 if (err) {
307 lderr(cct) << __func__ << " factory return error " << err <<
308 " with description: " << ss.str() << dendl;
309 }
310 return ca_impl;
311 }
312
313
314 template <std::size_t KeySizeV, std::size_t IvSizeV>
315 static inline
316 bool evp_sym_transform(CephContext* const cct,
317 const EVP_CIPHER* const type,
318 unsigned char* const out,
319 const unsigned char* const in,
320 const size_t size,
321 const unsigned char* const iv,
322 const unsigned char* const key,
323 const bool encrypt)
324 {
325 using pctx_t = \
326 std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>;
327 pctx_t pctx{ EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free };
328
329 if (!pctx) {
330 return false;
331 }
332
333 if (1 != EVP_CipherInit_ex(pctx.get(), type, nullptr,
334 nullptr, nullptr, encrypt)) {
335 ldout(cct, 5) << "EVP: failed to 1st initialization stage" << dendl;
336 return false;
337 }
338
339 // we want to support ciphers that don't use IV at all like AES-256-ECB
340 if constexpr (static_cast<bool>(IvSizeV)) {
341 ceph_assert(EVP_CIPHER_CTX_iv_length(pctx.get()) == IvSizeV);
342 ceph_assert(EVP_CIPHER_CTX_block_size(pctx.get()) == IvSizeV);
343 }
344 ceph_assert(EVP_CIPHER_CTX_key_length(pctx.get()) == KeySizeV);
345
346 if (1 != EVP_CipherInit_ex(pctx.get(), nullptr, nullptr, key, iv, encrypt)) {
347 ldout(cct, 5) << "EVP: failed to 2nd initialization stage" << dendl;
348 return false;
349 }
350
351 // disable padding
352 if (1 != EVP_CIPHER_CTX_set_padding(pctx.get(), 0)) {
353 ldout(cct, 5) << "EVP: cannot disable PKCS padding" << dendl;
354 return false;
355 }
356
357 // operate!
358 int written = 0;
359 ceph_assert(size <= static_cast<size_t>(std::numeric_limits<int>::max()));
360 if (1 != EVP_CipherUpdate(pctx.get(), out, &written, in, size)) {
361 ldout(cct, 5) << "EVP: EVP_CipherUpdate failed" << dendl;
362 return false;
363 }
364
365 int finally_written = 0;
366 static_assert(sizeof(*out) == 1);
367 if (1 != EVP_CipherFinal_ex(pctx.get(), out + written, &finally_written)) {
368 ldout(cct, 5) << "EVP: EVP_CipherFinal_ex failed" << dendl;
369 return false;
370 }
371
372 // padding is disabled so EVP_CipherFinal_ex should not append anything
373 ceph_assert(finally_written == 0);
374 return (written + finally_written) == static_cast<int>(size);
375 }
376
377
378 /**
379 * Encryption in CBC mode. Chunked to 4K blocks. Offset is used as IV for each 4K block.
380 *
381 *
382 *
383 * A. Encryption
384 * 1. Input is split to 4K chunks + remainder in one, smaller chunk
385 * 2. Each full chunk is encrypted separately with CBC chained mode, with initial IV derived from offset
386 * 3. Last chunk is 16*m + n.
387 * 4. 16*m bytes are encrypted with CBC chained mode, with initial IV derived from offset
388 * 5. Last n bytes are xor-ed with pattern obtained by CBC encryption of
389 * last encrypted 16 byte block <16m-16, 16m-15) with IV = {0}.
390 * 6. (Special case) If m == 0 then last n bytes are xor-ed with pattern
391 * obtained by CBC encryption of {0} with IV derived from offset
392 *
393 * B. Decryption
394 * 1. Input is split to 4K chunks + remainder in one, smaller chunk
395 * 2. Each full chunk is decrypted separately with CBC chained mode, with initial IV derived from offset
396 * 3. Last chunk is 16*m + n.
397 * 4. 16*m bytes are decrypted with CBC chained mode, with initial IV derived from offset
398 * 5. Last n bytes are xor-ed with pattern obtained by CBC ENCRYPTION of
399 * last (still encrypted) 16 byte block <16m-16,16m-15) with IV = {0}
400 * 6. (Special case) If m == 0 then last n bytes are xor-ed with pattern
401 * obtained by CBC ENCRYPTION of {0} with IV derived from offset
402 */
403 class AES_256_CBC : public BlockCrypt {
404 public:
405 static const size_t AES_256_KEYSIZE = 256 / 8;
406 static const size_t AES_256_IVSIZE = 128 / 8;
407 static const size_t CHUNK_SIZE = 4096;
408 private:
409 static const uint8_t IV[AES_256_IVSIZE];
410 CephContext* cct;
411 uint8_t key[AES_256_KEYSIZE];
412 public:
413 explicit AES_256_CBC(CephContext* cct): cct(cct) {
414 }
415 ~AES_256_CBC() {
416 ::ceph::crypto::zeroize_for_security(key, AES_256_KEYSIZE);
417 }
418 bool set_key(const uint8_t* _key, size_t key_size) {
419 if (key_size != AES_256_KEYSIZE) {
420 return false;
421 }
422 memcpy(key, _key, AES_256_KEYSIZE);
423 return true;
424 }
425 size_t get_block_size() {
426 return CHUNK_SIZE;
427 }
428
429 bool cbc_transform(unsigned char* out,
430 const unsigned char* in,
431 const size_t size,
432 const unsigned char (&iv)[AES_256_IVSIZE],
433 const unsigned char (&key)[AES_256_KEYSIZE],
434 bool encrypt)
435 {
436 return evp_sym_transform<AES_256_KEYSIZE, AES_256_IVSIZE>(
437 cct, EVP_aes_256_cbc(), out, in, size, iv, key, encrypt);
438 }
439
440 bool cbc_transform(unsigned char* out,
441 const unsigned char* in,
442 size_t size,
443 off_t stream_offset,
444 const unsigned char (&key)[AES_256_KEYSIZE],
445 bool encrypt)
446 {
447 static std::atomic<bool> failed_to_get_crypto(false);
448 CryptoAccelRef crypto_accel;
449 if (! failed_to_get_crypto.load())
450 {
451 crypto_accel = get_crypto_accel(cct);
452 if (!crypto_accel)
453 failed_to_get_crypto = true;
454 }
455 bool result = true;
456 unsigned char iv[AES_256_IVSIZE];
457 for (size_t offset = 0; result && (offset < size); offset += CHUNK_SIZE) {
458 size_t process_size = offset + CHUNK_SIZE <= size ? CHUNK_SIZE : size - offset;
459 prepare_iv(iv, stream_offset + offset);
460 if (crypto_accel != nullptr) {
461 if (encrypt) {
462 result = crypto_accel->cbc_encrypt(out + offset, in + offset,
463 process_size, iv, key);
464 } else {
465 result = crypto_accel->cbc_decrypt(out + offset, in + offset,
466 process_size, iv, key);
467 }
468 } else {
469 result = cbc_transform(
470 out + offset, in + offset, process_size,
471 iv, key, encrypt);
472 }
473 }
474 return result;
475 }
476
477
478 bool encrypt(bufferlist& input,
479 off_t in_ofs,
480 size_t size,
481 bufferlist& output,
482 off_t stream_offset)
483 {
484 bool result = false;
485 size_t aligned_size = size / AES_256_IVSIZE * AES_256_IVSIZE;
486 size_t unaligned_rest_size = size - aligned_size;
487 output.clear();
488 buffer::ptr buf(aligned_size + AES_256_IVSIZE);
489 unsigned char* buf_raw = reinterpret_cast<unsigned char*>(buf.c_str());
490 const unsigned char* input_raw = reinterpret_cast<const unsigned char*>(input.c_str());
491
492 /* encrypt main bulk of data */
493 result = cbc_transform(buf_raw,
494 input_raw + in_ofs,
495 aligned_size,
496 stream_offset, key, true);
497 if (result && (unaligned_rest_size > 0)) {
498 /* remainder to encrypt */
499 if (aligned_size % CHUNK_SIZE > 0) {
500 /* use last chunk for unaligned part */
501 unsigned char iv[AES_256_IVSIZE] = {0};
502 result = cbc_transform(buf_raw + aligned_size,
503 buf_raw + aligned_size - AES_256_IVSIZE,
504 AES_256_IVSIZE,
505 iv, key, true);
506 } else {
507 /* 0 full blocks in current chunk, use IV as base for unaligned part */
508 unsigned char iv[AES_256_IVSIZE] = {0};
509 unsigned char data[AES_256_IVSIZE];
510 prepare_iv(data, stream_offset + aligned_size);
511 result = cbc_transform(buf_raw + aligned_size,
512 data,
513 AES_256_IVSIZE,
514 iv, key, true);
515 }
516 if (result) {
517 for(size_t i = aligned_size; i < size; i++) {
518 *(buf_raw + i) ^= *(input_raw + in_ofs + i);
519 }
520 }
521 }
522 if (result) {
523 ldout(cct, 25) << "Encrypted " << size << " bytes"<< dendl;
524 buf.set_length(size);
525 output.append(buf);
526 } else {
527 ldout(cct, 5) << "Failed to encrypt" << dendl;
528 }
529 return result;
530 }
531
532
533 bool decrypt(bufferlist& input,
534 off_t in_ofs,
535 size_t size,
536 bufferlist& output,
537 off_t stream_offset)
538 {
539 bool result = false;
540 size_t aligned_size = size / AES_256_IVSIZE * AES_256_IVSIZE;
541 size_t unaligned_rest_size = size - aligned_size;
542 output.clear();
543 buffer::ptr buf(aligned_size + AES_256_IVSIZE);
544 unsigned char* buf_raw = reinterpret_cast<unsigned char*>(buf.c_str());
545 unsigned char* input_raw = reinterpret_cast<unsigned char*>(input.c_str());
546
547 /* decrypt main bulk of data */
548 result = cbc_transform(buf_raw,
549 input_raw + in_ofs,
550 aligned_size,
551 stream_offset, key, false);
552 if (result && unaligned_rest_size > 0) {
553 /* remainder to decrypt */
554 if (aligned_size % CHUNK_SIZE > 0) {
555 /*use last chunk for unaligned part*/
556 unsigned char iv[AES_256_IVSIZE] = {0};
557 result = cbc_transform(buf_raw + aligned_size,
558 input_raw + in_ofs + aligned_size - AES_256_IVSIZE,
559 AES_256_IVSIZE,
560 iv, key, true);
561 } else {
562 /* 0 full blocks in current chunk, use IV as base for unaligned part */
563 unsigned char iv[AES_256_IVSIZE] = {0};
564 unsigned char data[AES_256_IVSIZE];
565 prepare_iv(data, stream_offset + aligned_size);
566 result = cbc_transform(buf_raw + aligned_size,
567 data,
568 AES_256_IVSIZE,
569 iv, key, true);
570 }
571 if (result) {
572 for(size_t i = aligned_size; i < size; i++) {
573 *(buf_raw + i) ^= *(input_raw + in_ofs + i);
574 }
575 }
576 }
577 if (result) {
578 ldout(cct, 25) << "Decrypted " << size << " bytes"<< dendl;
579 buf.set_length(size);
580 output.append(buf);
581 } else {
582 ldout(cct, 5) << "Failed to decrypt" << dendl;
583 }
584 return result;
585 }
586
587
588 void prepare_iv(unsigned char (&iv)[AES_256_IVSIZE], off_t offset) {
589 off_t index = offset / AES_256_IVSIZE;
590 off_t i = AES_256_IVSIZE - 1;
591 unsigned int val;
592 unsigned int carry = 0;
593 while (i>=0) {
594 val = (index & 0xff) + IV[i] + carry;
595 iv[i] = val;
596 carry = val >> 8;
597 index = index >> 8;
598 i--;
599 }
600 }
601 };
602
603
604 std::unique_ptr<BlockCrypt> AES_256_CBC_create(CephContext* cct, const uint8_t* key, size_t len)
605 {
606 auto cbc = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(cct));
607 cbc->set_key(key, AES_256_KEYSIZE);
608 return cbc;
609 }
610
611
612 const uint8_t AES_256_CBC::IV[AES_256_CBC::AES_256_IVSIZE] =
613 { 'a', 'e', 's', '2', '5', '6', 'i', 'v', '_', 'c', 't', 'r', '1', '3', '3', '7' };
614
615
616 bool AES_256_ECB_encrypt(CephContext* cct,
617 const uint8_t* key,
618 size_t key_size,
619 const uint8_t* data_in,
620 uint8_t* data_out,
621 size_t data_size)
622 {
623 if (key_size == AES_256_KEYSIZE) {
624 return evp_sym_transform<AES_256_KEYSIZE, 0 /* no IV in ECB */>(
625 cct, EVP_aes_256_ecb(), data_out, data_in, data_size,
626 nullptr /* no IV in ECB */, key, true /* encrypt */);
627 } else {
628 ldout(cct, 5) << "Key size must be 256 bits long" << dendl;
629 return false;
630 }
631 }
632
633
634 RGWGetObj_BlockDecrypt::RGWGetObj_BlockDecrypt(CephContext* cct,
635 RGWGetObj_Filter* next,
636 std::unique_ptr<BlockCrypt> crypt):
637 RGWGetObj_Filter(next),
638 cct(cct),
639 crypt(std::move(crypt)),
640 enc_begin_skip(0),
641 ofs(0),
642 end(0),
643 cache()
644 {
645 block_size = this->crypt->get_block_size();
646 }
647
648 RGWGetObj_BlockDecrypt::~RGWGetObj_BlockDecrypt() {
649 }
650
651 int RGWGetObj_BlockDecrypt::read_manifest(const DoutPrefixProvider *dpp, bufferlist& manifest_bl) {
652 parts_len.clear();
653 RGWObjManifest manifest;
654 if (manifest_bl.length()) {
655 auto miter = manifest_bl.cbegin();
656 try {
657 decode(manifest, miter);
658 } catch (buffer::error& err) {
659 ldpp_dout(dpp, 0) << "ERROR: couldn't decode manifest" << dendl;
660 return -EIO;
661 }
662 RGWObjManifest::obj_iterator mi;
663 for (mi = manifest.obj_begin(dpp); mi != manifest.obj_end(dpp); ++mi) {
664 if (mi.get_cur_stripe() == 0) {
665 parts_len.push_back(0);
666 }
667 parts_len.back() += mi.get_stripe_size();
668 }
669 if (cct->_conf->subsys.should_gather<ceph_subsys_rgw, 20>()) {
670 for (size_t i = 0; i<parts_len.size(); i++) {
671 ldpp_dout(dpp, 20) << "Manifest part " << i << ", size=" << parts_len[i] << dendl;
672 }
673 }
674 }
675 return 0;
676 }
677
678 int RGWGetObj_BlockDecrypt::fixup_range(off_t& bl_ofs, off_t& bl_end) {
679 off_t inp_ofs = bl_ofs;
680 off_t inp_end = bl_end;
681 if (parts_len.size() > 0) {
682 off_t in_ofs = bl_ofs;
683 off_t in_end = bl_end;
684
685 size_t i = 0;
686 while (i<parts_len.size() && (in_ofs >= (off_t)parts_len[i])) {
687 in_ofs -= parts_len[i];
688 i++;
689 }
690 //in_ofs is inside block i
691 size_t j = 0;
692 while (j<(parts_len.size() - 1) && (in_end >= (off_t)parts_len[j])) {
693 in_end -= parts_len[j];
694 j++;
695 }
696 //in_end is inside part j, OR j is the last part
697
698 size_t rounded_end = ( in_end & ~(block_size - 1) ) + (block_size - 1);
699 if (rounded_end > parts_len[j]) {
700 rounded_end = parts_len[j] - 1;
701 }
702
703 enc_begin_skip = in_ofs & (block_size - 1);
704 ofs = bl_ofs - enc_begin_skip;
705 end = bl_end;
706 bl_end += rounded_end - in_end;
707 bl_ofs = std::min(bl_ofs - enc_begin_skip, bl_end);
708 }
709 else
710 {
711 enc_begin_skip = bl_ofs & (block_size - 1);
712 ofs = bl_ofs & ~(block_size - 1);
713 end = bl_end;
714 bl_ofs = bl_ofs & ~(block_size - 1);
715 bl_end = ( bl_end & ~(block_size - 1) ) + (block_size - 1);
716 }
717 ldout(cct, 20) << "fixup_range [" << inp_ofs << "," << inp_end
718 << "] => [" << bl_ofs << "," << bl_end << "]" << dendl;
719 return 0;
720 }
721
722 int RGWGetObj_BlockDecrypt::process(bufferlist& in, size_t part_ofs, size_t size)
723 {
724 bufferlist data;
725 if (!crypt->decrypt(in, 0, size, data, part_ofs)) {
726 return -ERR_INTERNAL_ERROR;
727 }
728 off_t send_size = size - enc_begin_skip;
729 if (ofs + enc_begin_skip + send_size > end + 1) {
730 send_size = end + 1 - ofs - enc_begin_skip;
731 }
732 int res = next->handle_data(data, enc_begin_skip, send_size);
733 enc_begin_skip = 0;
734 ofs += size;
735 in.splice(0, size);
736 return res;
737 }
738
739 int RGWGetObj_BlockDecrypt::handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) {
740 ldout(cct, 25) << "Decrypt " << bl_len << " bytes" << dendl;
741 bl.begin(bl_ofs).copy(bl_len, cache);
742
743 int res = 0;
744 size_t part_ofs = ofs;
745 for (size_t part : parts_len) {
746 if (part_ofs >= part) {
747 part_ofs -= part;
748 } else if (part_ofs + cache.length() >= part) {
749 // flush data up to part boundaries, aligned or not
750 res = process(cache, part_ofs, part - part_ofs);
751 if (res < 0) {
752 return res;
753 }
754 part_ofs = 0;
755 } else {
756 break;
757 }
758 }
759 // write up to block boundaries, aligned only
760 off_t aligned_size = cache.length() & ~(block_size - 1);
761 if (aligned_size > 0) {
762 res = process(cache, part_ofs, aligned_size);
763 }
764 return res;
765 }
766
767 /**
768 * flush remainder of data to output
769 */
770 int RGWGetObj_BlockDecrypt::flush() {
771 ldout(cct, 25) << "Decrypt flushing " << cache.length() << " bytes" << dendl;
772 int res = 0;
773 size_t part_ofs = ofs;
774 for (size_t part : parts_len) {
775 if (part_ofs >= part) {
776 part_ofs -= part;
777 } else if (part_ofs + cache.length() >= part) {
778 // flush data up to part boundaries, aligned or not
779 res = process(cache, part_ofs, part - part_ofs);
780 if (res < 0) {
781 return res;
782 }
783 part_ofs = 0;
784 } else {
785 break;
786 }
787 }
788 // flush up to block boundaries, aligned or not
789 if (cache.length() > 0) {
790 res = process(cache, part_ofs, cache.length());
791 }
792 return res;
793 }
794
795 RGWPutObj_BlockEncrypt::RGWPutObj_BlockEncrypt(CephContext* cct,
796 rgw::putobj::DataProcessor *next,
797 std::unique_ptr<BlockCrypt> crypt)
798 : Pipe(next),
799 cct(cct),
800 crypt(std::move(crypt)),
801 block_size(this->crypt->get_block_size())
802 {
803 }
804
805 int RGWPutObj_BlockEncrypt::process(bufferlist&& data, uint64_t logical_offset)
806 {
807 ldout(cct, 25) << "Encrypt " << data.length() << " bytes" << dendl;
808
809 // adjust logical offset to beginning of cached data
810 ceph_assert(logical_offset >= cache.length());
811 logical_offset -= cache.length();
812
813 const bool flush = (data.length() == 0);
814 cache.claim_append(data);
815
816 uint64_t proc_size = cache.length() & ~(block_size - 1);
817 if (flush) {
818 proc_size = cache.length();
819 }
820 if (proc_size > 0) {
821 bufferlist in, out;
822 cache.splice(0, proc_size, &in);
823 if (!crypt->encrypt(in, 0, proc_size, out, logical_offset)) {
824 return -ERR_INTERNAL_ERROR;
825 }
826 int r = Pipe::process(std::move(out), logical_offset);
827 logical_offset += proc_size;
828 if (r < 0)
829 return r;
830 }
831
832 if (flush) {
833 /*replicate 0-sized handle_data*/
834 return Pipe::process({}, logical_offset);
835 }
836 return 0;
837 }
838
839
840 std::string create_random_key_selector(CephContext * const cct) {
841 char random[AES_256_KEYSIZE];
842 cct->random()->get_bytes(&random[0], sizeof(random));
843 return std::string(random, sizeof(random));
844 }
845
846 typedef enum {
847 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM=0,
848 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY,
849 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5,
850 X_AMZ_SERVER_SIDE_ENCRYPTION,
851 X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID,
852 X_AMZ_SERVER_SIDE_ENCRYPTION_CONTEXT,
853 X_AMZ_SERVER_SIDE_ENCRYPTION_LAST
854 } crypt_option_e;
855
856 typedef struct {
857 const char* http_header_name;
858 const std::string post_part_name;
859 } crypt_option_names;
860
861 static const crypt_option_names crypt_options[] = {
862 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", "x-amz-server-side-encryption-customer-algorithm"},
863 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", "x-amz-server-side-encryption-customer-key"},
864 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "x-amz-server-side-encryption-customer-key-md5"},
865 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION", "x-amz-server-side-encryption"},
866 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID", "x-amz-server-side-encryption-aws-kms-key-id"},
867 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CONTEXT", "x-amz-server-side-encryption-context"},
868 };
869
870 static std::string_view get_crypt_attribute(
871 const RGWEnv* env,
872 std::map<std::string,
873 RGWPostObj_ObjStore::post_form_part,
874 const ltstr_nocase>* parts,
875 crypt_option_e option)
876 {
877 static_assert(
878 X_AMZ_SERVER_SIDE_ENCRYPTION_LAST == sizeof(crypt_options)/sizeof(*crypt_options),
879 "Missing items in crypt_options");
880 if (parts != nullptr) {
881 auto iter
882 = parts->find(crypt_options[option].post_part_name);
883 if (iter == parts->end())
884 return std::string_view();
885 bufferlist& data = iter->second.data;
886 std::string_view str = std::string_view(data.c_str(), data.length());
887 return rgw_trim_whitespace(str);
888 } else {
889 const char* hdr = env->get(crypt_options[option].http_header_name, nullptr);
890 if (hdr != nullptr) {
891 return std::string_view(hdr);
892 } else {
893 return std::string_view();
894 }
895 }
896 }
897
898
899 int rgw_s3_prepare_encrypt(struct req_state* s,
900 std::map<std::string, ceph::bufferlist>& attrs,
901 std::map<std::string,
902 RGWPostObj_ObjStore::post_form_part,
903 const ltstr_nocase>* parts,
904 std::unique_ptr<BlockCrypt>* block_crypt,
905 std::map<std::string, std::string>& crypt_http_responses)
906 {
907 int res = 0;
908 crypt_http_responses.clear();
909 {
910 std::string_view req_sse_ca =
911 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM);
912 if (! req_sse_ca.empty()) {
913 if (req_sse_ca != "AES256") {
914 ldpp_dout(s, 5) << "ERROR: Invalid value for header "
915 << "x-amz-server-side-encryption-customer-algorithm"
916 << dendl;
917 s->err.message = "The requested encryption algorithm is not valid, must be AES256.";
918 return -ERR_INVALID_ENCRYPTION_ALGORITHM;
919 }
920 if (s->cct->_conf->rgw_crypt_require_ssl &&
921 !rgw_transport_is_secure(s->cct, *s->info.env)) {
922 ldpp_dout(s, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl;
923 return -ERR_INVALID_REQUEST;
924 }
925
926 std::string key_bin;
927 try {
928 key_bin = from_base64(
929 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY) );
930 } catch (...) {
931 ldpp_dout(s, 5) << "ERROR: rgw_s3_prepare_encrypt invalid encryption "
932 << "key which contains character that is not base64 encoded."
933 << dendl;
934 s->err.message = "Requests specifying Server Side Encryption with Customer "
935 "provided keys must provide an appropriate secret key.";
936 return -EINVAL;
937 }
938
939 if (key_bin.size() != AES_256_CBC::AES_256_KEYSIZE) {
940 ldpp_dout(s, 5) << "ERROR: invalid encryption key size" << dendl;
941 s->err.message = "Requests specifying Server Side Encryption with Customer "
942 "provided keys must provide an appropriate secret key.";
943 return -EINVAL;
944 }
945
946 std::string_view keymd5 =
947 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5);
948
949 std::string keymd5_bin;
950 try {
951 keymd5_bin = from_base64(keymd5);
952 } catch (...) {
953 ldpp_dout(s, 5) << "ERROR: rgw_s3_prepare_encrypt invalid encryption key "
954 << "md5 which contains character that is not base64 encoded."
955 << dendl;
956 s->err.message = "Requests specifying Server Side Encryption with Customer "
957 "provided keys must provide an appropriate secret key md5.";
958 return -EINVAL;
959 }
960
961 if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
962 ldpp_dout(s, 5) << "ERROR: Invalid key md5 size" << dendl;
963 s->err.message = "Requests specifying Server Side Encryption with Customer "
964 "provided keys must provide an appropriate secret key md5.";
965 return -EINVAL;
966 }
967
968 MD5 key_hash;
969 unsigned char key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE];
970 key_hash.Update(reinterpret_cast<const unsigned char*>(key_bin.c_str()), key_bin.size());
971 key_hash.Final(key_hash_res);
972
973 if (memcmp(key_hash_res, keymd5_bin.c_str(), CEPH_CRYPTO_MD5_DIGESTSIZE) != 0) {
974 ldpp_dout(s, 5) << "ERROR: Invalid key md5 hash" << dendl;
975 s->err.message = "The calculated MD5 hash of the key did not match the hash that was provided.";
976 return -EINVAL;
977 }
978
979 set_attr(attrs, RGW_ATTR_CRYPT_MODE, "SSE-C-AES256");
980 set_attr(attrs, RGW_ATTR_CRYPT_KEYMD5, keymd5_bin);
981
982 if (block_crypt) {
983 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
984 aes->set_key(reinterpret_cast<const uint8_t*>(key_bin.c_str()), AES_256_KEYSIZE);
985 *block_crypt = std::move(aes);
986 }
987
988 crypt_http_responses["x-amz-server-side-encryption-customer-algorithm"] = "AES256";
989 crypt_http_responses["x-amz-server-side-encryption-customer-key-MD5"] = std::string(keymd5);
990 return 0;
991 } else {
992 std::string_view customer_key =
993 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY);
994 if (!customer_key.empty()) {
995 ldpp_dout(s, 5) << "ERROR: SSE-C encryption request is missing the header "
996 << "x-amz-server-side-encryption-customer-algorithm"
997 << dendl;
998 s->err.message = "Requests specifying Server Side Encryption with Customer "
999 "provided keys must provide a valid encryption algorithm.";
1000 return -EINVAL;
1001 }
1002
1003 std::string_view customer_key_md5 =
1004 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5);
1005 if (!customer_key_md5.empty()) {
1006 ldpp_dout(s, 5) << "ERROR: SSE-C encryption request is missing the header "
1007 << "x-amz-server-side-encryption-customer-algorithm"
1008 << dendl;
1009 s->err.message = "Requests specifying Server Side Encryption with Customer "
1010 "provided keys must provide a valid encryption algorithm.";
1011 return -EINVAL;
1012 }
1013 }
1014
1015 /* AMAZON server side encryption with KMS (key management service) */
1016 std::string_view req_sse =
1017 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION);
1018 if (! req_sse.empty()) {
1019
1020 if (s->cct->_conf->rgw_crypt_require_ssl &&
1021 !rgw_transport_is_secure(s->cct, *s->info.env)) {
1022 ldpp_dout(s, 5) << "ERROR: insecure request, rgw_crypt_require_ssl is set" << dendl;
1023 return -ERR_INVALID_REQUEST;
1024 }
1025
1026 if (req_sse == "aws:kms") {
1027 std::string_view context =
1028 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CONTEXT);
1029 std::string cooked_context;
1030 if ((res = make_canonical_context(s, context, cooked_context)))
1031 return res;
1032 std::string_view key_id =
1033 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID);
1034 if (key_id.empty()) {
1035 ldpp_dout(s, 5) << "ERROR: not provide a valid key id" << dendl;
1036 s->err.message = "Server Side Encryption with KMS managed key requires "
1037 "HTTP header x-amz-server-side-encryption-aws-kms-key-id";
1038 return -ERR_INVALID_ACCESS_KEY;
1039 }
1040 /* try to retrieve actual key */
1041 std::string key_selector = create_random_key_selector(s->cct);
1042 set_attr(attrs, RGW_ATTR_CRYPT_MODE, "SSE-KMS");
1043 set_attr(attrs, RGW_ATTR_CRYPT_KEYID, key_id);
1044 set_attr(attrs, RGW_ATTR_CRYPT_KEYSEL, key_selector);
1045 set_attr(attrs, RGW_ATTR_CRYPT_CONTEXT, cooked_context);
1046 std::string actual_key;
1047 res = make_actual_key_from_kms(s->cct, attrs, actual_key);
1048 if (res != 0) {
1049 ldpp_dout(s, 5) << "ERROR: failed to retrieve actual key from key_id: " << key_id << dendl;
1050 s->err.message = "Failed to retrieve the actual key, kms-keyid: " + std::string(key_id);
1051 return res;
1052 }
1053 if (actual_key.size() != AES_256_KEYSIZE) {
1054 ldpp_dout(s, 5) << "ERROR: key obtained from key_id:" <<
1055 key_id << " is not 256 bit size" << dendl;
1056 s->err.message = "KMS provided an invalid key for the given kms-keyid.";
1057 return -ERR_INVALID_ACCESS_KEY;
1058 }
1059
1060 if (block_crypt) {
1061 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
1062 aes->set_key(reinterpret_cast<const uint8_t*>(actual_key.c_str()), AES_256_KEYSIZE);
1063 *block_crypt = std::move(aes);
1064 }
1065 ::ceph::crypto::zeroize_for_security(actual_key.data(), actual_key.length());
1066
1067 crypt_http_responses["x-amz-server-side-encryption"] = "aws:kms";
1068 crypt_http_responses["x-amz-server-side-encryption-aws-kms-key-id"] = std::string(key_id);
1069 crypt_http_responses["x-amz-server-side-encryption-context"] = std::move(cooked_context);
1070 return 0;
1071 } else if (req_sse == "AES256") {
1072 /* if a default encryption key was provided, we will use it for SSE-S3 */
1073 } else {
1074 ldpp_dout(s, 5) << "ERROR: Invalid value for header x-amz-server-side-encryption"
1075 << dendl;
1076 s->err.message = "Server Side Encryption with KMS managed key requires "
1077 "HTTP header x-amz-server-side-encryption : aws:kms or AES256";
1078 return -EINVAL;
1079 }
1080 } else {
1081 /* x-amz-server-side-encryption not present or empty */
1082 std::string_view key_id =
1083 get_crypt_attribute(s->info.env, parts,
1084 X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID);
1085 if (!key_id.empty()) {
1086 ldpp_dout(s, 5) << "ERROR: SSE-KMS encryption request is missing the header "
1087 << "x-amz-server-side-encryption"
1088 << dendl;
1089 s->err.message = "Server Side Encryption with KMS managed key requires "
1090 "HTTP header x-amz-server-side-encryption : aws:kms";
1091 return -EINVAL;
1092 }
1093 }
1094
1095 /* no other encryption mode, check if default encryption is selected */
1096 if (s->cct->_conf->rgw_crypt_default_encryption_key != "") {
1097 std::string master_encryption_key;
1098 try {
1099 master_encryption_key = from_base64(s->cct->_conf->rgw_crypt_default_encryption_key);
1100 } catch (...) {
1101 ldpp_dout(s, 5) << "ERROR: rgw_s3_prepare_encrypt invalid default encryption key "
1102 << "which contains character that is not base64 encoded."
1103 << dendl;
1104 s->err.message = "Requests specifying Server Side Encryption with Customer "
1105 "provided keys must provide an appropriate secret key.";
1106 return -EINVAL;
1107 }
1108
1109 if (master_encryption_key.size() != 256 / 8) {
1110 ldpp_dout(s, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl;
1111 /* not an error to return; missing encryption does not inhibit processing */
1112 return 0;
1113 }
1114
1115 set_attr(attrs, RGW_ATTR_CRYPT_MODE, "RGW-AUTO");
1116 std::string key_selector = create_random_key_selector(s->cct);
1117 set_attr(attrs, RGW_ATTR_CRYPT_KEYSEL, key_selector);
1118
1119 uint8_t actual_key[AES_256_KEYSIZE];
1120 if (AES_256_ECB_encrypt(s->cct,
1121 reinterpret_cast<const uint8_t*>(master_encryption_key.c_str()), AES_256_KEYSIZE,
1122 reinterpret_cast<const uint8_t*>(key_selector.c_str()),
1123 actual_key, AES_256_KEYSIZE) != true) {
1124 ::ceph::crypto::zeroize_for_security(actual_key, sizeof(actual_key));
1125 return -EIO;
1126 }
1127 if (block_crypt) {
1128 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
1129 aes->set_key(reinterpret_cast<const uint8_t*>(actual_key), AES_256_KEYSIZE);
1130 *block_crypt = std::move(aes);
1131 }
1132 ::ceph::crypto::zeroize_for_security(actual_key, sizeof(actual_key));
1133 return 0;
1134 }
1135 }
1136 /*no encryption*/
1137 return 0;
1138 }
1139
1140
1141 int rgw_s3_prepare_decrypt(struct req_state* s,
1142 map<string, bufferlist>& attrs,
1143 std::unique_ptr<BlockCrypt>* block_crypt,
1144 std::map<std::string, std::string>& crypt_http_responses)
1145 {
1146 int res = 0;
1147 std::string stored_mode = get_str_attribute(attrs, RGW_ATTR_CRYPT_MODE);
1148 ldpp_dout(s, 15) << "Encryption mode: " << stored_mode << dendl;
1149
1150 const char *req_sse = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION", NULL);
1151 if (nullptr != req_sse && (s->op == OP_GET || s->op == OP_HEAD)) {
1152 return -ERR_INVALID_REQUEST;
1153 }
1154
1155 if (stored_mode == "SSE-C-AES256") {
1156 if (s->cct->_conf->rgw_crypt_require_ssl &&
1157 !rgw_transport_is_secure(s->cct, *s->info.env)) {
1158 ldpp_dout(s, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl;
1159 return -ERR_INVALID_REQUEST;
1160 }
1161 const char *req_cust_alg =
1162 s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", NULL);
1163
1164 if (nullptr == req_cust_alg) {
1165 ldpp_dout(s, 5) << "ERROR: Request for SSE-C encrypted object missing "
1166 << "x-amz-server-side-encryption-customer-algorithm"
1167 << dendl;
1168 s->err.message = "Requests specifying Server Side Encryption with Customer "
1169 "provided keys must provide a valid encryption algorithm.";
1170 return -EINVAL;
1171 } else if (strcmp(req_cust_alg, "AES256") != 0) {
1172 ldpp_dout(s, 5) << "ERROR: The requested encryption algorithm is not valid, must be AES256." << dendl;
1173 s->err.message = "The requested encryption algorithm is not valid, must be AES256.";
1174 return -ERR_INVALID_ENCRYPTION_ALGORITHM;
1175 }
1176
1177 std::string key_bin;
1178 try {
1179 key_bin = from_base64(s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", ""));
1180 } catch (...) {
1181 ldpp_dout(s, 5) << "ERROR: rgw_s3_prepare_decrypt invalid encryption key "
1182 << "which contains character that is not base64 encoded."
1183 << dendl;
1184 s->err.message = "Requests specifying Server Side Encryption with Customer "
1185 "provided keys must provide an appropriate secret key.";
1186 return -EINVAL;
1187 }
1188
1189 if (key_bin.size() != AES_256_CBC::AES_256_KEYSIZE) {
1190 ldpp_dout(s, 5) << "ERROR: Invalid encryption key size" << dendl;
1191 s->err.message = "Requests specifying Server Side Encryption with Customer "
1192 "provided keys must provide an appropriate secret key.";
1193 return -EINVAL;
1194 }
1195
1196 std::string keymd5 =
1197 s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "");
1198 std::string keymd5_bin;
1199 try {
1200 keymd5_bin = from_base64(keymd5);
1201 } catch (...) {
1202 ldpp_dout(s, 5) << "ERROR: rgw_s3_prepare_decrypt invalid encryption key md5 "
1203 << "which contains character that is not base64 encoded."
1204 << dendl;
1205 s->err.message = "Requests specifying Server Side Encryption with Customer "
1206 "provided keys must provide an appropriate secret key md5.";
1207 return -EINVAL;
1208 }
1209
1210
1211 if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
1212 ldpp_dout(s, 5) << "ERROR: Invalid key md5 size " << dendl;
1213 s->err.message = "Requests specifying Server Side Encryption with Customer "
1214 "provided keys must provide an appropriate secret key md5.";
1215 return -EINVAL;
1216 }
1217
1218 MD5 key_hash;
1219 uint8_t key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE];
1220 key_hash.Update(reinterpret_cast<const unsigned char*>(key_bin.c_str()), key_bin.size());
1221 key_hash.Final(key_hash_res);
1222
1223 if ((memcmp(key_hash_res, keymd5_bin.c_str(), CEPH_CRYPTO_MD5_DIGESTSIZE) != 0) ||
1224 (get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYMD5) != keymd5_bin)) {
1225 s->err.message = "The calculated MD5 hash of the key did not match the hash that was provided.";
1226 return -EINVAL;
1227 }
1228 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
1229 aes->set_key(reinterpret_cast<const uint8_t*>(key_bin.c_str()), AES_256_CBC::AES_256_KEYSIZE);
1230 if (block_crypt) *block_crypt = std::move(aes);
1231
1232 crypt_http_responses["x-amz-server-side-encryption-customer-algorithm"] = "AES256";
1233 crypt_http_responses["x-amz-server-side-encryption-customer-key-MD5"] = keymd5;
1234 return 0;
1235 }
1236
1237 if (stored_mode == "SSE-KMS") {
1238 if (s->cct->_conf->rgw_crypt_require_ssl &&
1239 !rgw_transport_is_secure(s->cct, *s->info.env)) {
1240 ldpp_dout(s, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl;
1241 return -ERR_INVALID_REQUEST;
1242 }
1243 /* try to retrieve actual key */
1244 std::string key_id = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYID);
1245 std::string actual_key;
1246 res = reconstitute_actual_key_from_kms(s->cct, attrs, actual_key);
1247 if (res != 0) {
1248 ldpp_dout(s, 10) << "ERROR: failed to retrieve actual key from key_id: " << key_id << dendl;
1249 s->err.message = "Failed to retrieve the actual key, kms-keyid: " + key_id;
1250 return res;
1251 }
1252 if (actual_key.size() != AES_256_KEYSIZE) {
1253 ldpp_dout(s, 0) << "ERROR: key obtained from key_id:" <<
1254 key_id << " is not 256 bit size" << dendl;
1255 s->err.message = "KMS provided an invalid key for the given kms-keyid.";
1256 return -ERR_INVALID_ACCESS_KEY;
1257 }
1258
1259 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
1260 aes->set_key(reinterpret_cast<const uint8_t*>(actual_key.c_str()), AES_256_KEYSIZE);
1261 actual_key.replace(0, actual_key.length(), actual_key.length(), '\000');
1262 if (block_crypt) *block_crypt = std::move(aes);
1263
1264 crypt_http_responses["x-amz-server-side-encryption"] = "aws:kms";
1265 crypt_http_responses["x-amz-server-side-encryption-aws-kms-key-id"] = key_id;
1266 return 0;
1267 }
1268
1269 if (stored_mode == "RGW-AUTO") {
1270 std::string master_encryption_key;
1271 try {
1272 master_encryption_key = from_base64(std::string(s->cct->_conf->rgw_crypt_default_encryption_key));
1273 } catch (...) {
1274 ldpp_dout(s, 5) << "ERROR: rgw_s3_prepare_decrypt invalid default encryption key "
1275 << "which contains character that is not base64 encoded."
1276 << dendl;
1277 s->err.message = "The default encryption key is not valid base64.";
1278 return -EINVAL;
1279 }
1280
1281 if (master_encryption_key.size() != 256 / 8) {
1282 ldpp_dout(s, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl;
1283 return -EIO;
1284 }
1285 std::string attr_key_selector = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYSEL);
1286 if (attr_key_selector.size() != AES_256_CBC::AES_256_KEYSIZE) {
1287 ldpp_dout(s, 0) << "ERROR: missing or invalid " RGW_ATTR_CRYPT_KEYSEL << dendl;
1288 return -EIO;
1289 }
1290 uint8_t actual_key[AES_256_KEYSIZE];
1291 if (AES_256_ECB_encrypt(s->cct,
1292 reinterpret_cast<const uint8_t*>(master_encryption_key.c_str()),
1293 AES_256_KEYSIZE,
1294 reinterpret_cast<const uint8_t*>(attr_key_selector.c_str()),
1295 actual_key, AES_256_KEYSIZE) != true) {
1296 ::ceph::crypto::zeroize_for_security(actual_key, sizeof(actual_key));
1297 return -EIO;
1298 }
1299 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
1300 aes->set_key(actual_key, AES_256_KEYSIZE);
1301 ::ceph::crypto::zeroize_for_security(actual_key, sizeof(actual_key));
1302 if (block_crypt) *block_crypt = std::move(aes);
1303 return 0;
1304 }
1305 /*no decryption*/
1306 return 0;
1307 }
1308
1309 /*********************************************************************
1310 * "BOTTOM OF FILE"
1311 * I've left some commented out lines above. They are there for
1312 * a reason, which I will explain. The "canonical" json constructed
1313 * by the code above as a crypto context must take a json object and
1314 * turn it into a unique determinstic fixed form. For most json
1315 * types this is easy. The hardest problem that is handled above is
1316 * detailing with unicode strings; they must be turned into
1317 * NFC form and sorted in a fixed order. Numbers, however,
1318 * are another story. Json makes no distinction between integers
1319 * and floating point, and both types have their problems.
1320 * Integers can overflow, so very large numbers are a problem.
1321 * Floating point is even worse; not all floating point numbers
1322 * can be represented accurately in c++ data types, and there
1323 * are many quirks regarding how overflow, underflow, and loss
1324 * of significance are handled.
1325 *
1326 * In this version of the code, I took the simplest answer, I
1327 * reject all numbers altogether. This is not ideal, but it's
1328 * the only choice that is guaranteed to be future compatible.
1329 * AWS S3 does not guarantee to support numbers at all; but it
1330 * actually converts all numbers into strings right off.
1331 * This has the interesting property that 7 and 007 are different,
1332 * but that 007 and "007" are the same. I would rather
1333 * treat numbers as a string of digits and have logic
1334 * to produce the "most compact" equivalent form. This can
1335 * fix all the overflow/underflow problems, but it requires
1336 * fixing the json parser part, and I put that problem off.
1337 *
1338 * The commented code above indicates places in this code that
1339 * will need to be revised depending on future work in this area.
1340 * Removing those comments makes that work harder.
1341 * February 25, 2021
1342 *********************************************************************/