]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_crypt.cc
import ceph 15.2.10
[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 <rgw/rgw_op.h>
9 #include <rgw/rgw_crypt.h>
10 #include <auth/Crypto.h>
11 #include <rgw/rgw_b64.h>
12 #include <rgw/rgw_rest_s3.h>
13 #include "include/ceph_assert.h"
14 #include <boost/utility/string_view.hpp>
15 #include "crypto/crypto_accel.h"
16 #include "crypto/crypto_plugin.h"
17 #include "rgw/rgw_kms.h"
18
19 #include <openssl/evp.h>
20
21 #define dout_context g_ceph_context
22 #define dout_subsys ceph_subsys_rgw
23
24 using namespace rgw;
25
26
27 CryptoAccelRef get_crypto_accel(CephContext *cct)
28 {
29 CryptoAccelRef ca_impl = nullptr;
30 stringstream ss;
31 PluginRegistry *reg = cct->get_plugin_registry();
32 string crypto_accel_type = cct->_conf->plugin_crypto_accelerator;
33
34 CryptoPlugin *factory = dynamic_cast<CryptoPlugin*>(reg->get_with_load("crypto", crypto_accel_type));
35 if (factory == nullptr) {
36 lderr(cct) << __func__ << " cannot load crypto accelerator of type " << crypto_accel_type << dendl;
37 return nullptr;
38 }
39 int err = factory->factory(&ca_impl, &ss);
40 if (err) {
41 lderr(cct) << __func__ << " factory return error " << err <<
42 " with description: " << ss.str() << dendl;
43 }
44 return ca_impl;
45 }
46
47
48 template <std::size_t KeySizeV, std::size_t IvSizeV>
49 static inline
50 bool evp_sym_transform(CephContext* const cct,
51 const EVP_CIPHER* const type,
52 unsigned char* const out,
53 const unsigned char* const in,
54 const size_t size,
55 const unsigned char* const iv,
56 const unsigned char* const key,
57 const bool encrypt)
58 {
59 using pctx_t = \
60 std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>;
61 pctx_t pctx{ EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free };
62
63 if (!pctx) {
64 return false;
65 }
66
67 if (1 != EVP_CipherInit_ex(pctx.get(), type, nullptr,
68 nullptr, nullptr, encrypt)) {
69 ldout(cct, 5) << "EVP: failed to 1st initialization stage" << dendl;
70 return false;
71 }
72
73 // we want to support ciphers that don't use IV at all like AES-256-ECB
74 if constexpr (static_cast<bool>(IvSizeV)) {
75 ceph_assert(EVP_CIPHER_CTX_iv_length(pctx.get()) == IvSizeV);
76 ceph_assert(EVP_CIPHER_CTX_block_size(pctx.get()) == IvSizeV);
77 }
78 ceph_assert(EVP_CIPHER_CTX_key_length(pctx.get()) == KeySizeV);
79
80 if (1 != EVP_CipherInit_ex(pctx.get(), nullptr, nullptr, key, iv, encrypt)) {
81 ldout(cct, 5) << "EVP: failed to 2nd initialization stage" << dendl;
82 return false;
83 }
84
85 // disable padding
86 if (1 != EVP_CIPHER_CTX_set_padding(pctx.get(), 0)) {
87 ldout(cct, 5) << "EVP: cannot disable PKCS padding" << dendl;
88 return false;
89 }
90
91 // operate!
92 int written = 0;
93 ceph_assert(size <= static_cast<size_t>(std::numeric_limits<int>::max()));
94 if (1 != EVP_CipherUpdate(pctx.get(), out, &written, in, size)) {
95 ldout(cct, 5) << "EVP: EVP_CipherUpdate failed" << dendl;
96 return false;
97 }
98
99 int finally_written = 0;
100 static_assert(sizeof(*out) == 1);
101 if (1 != EVP_CipherFinal_ex(pctx.get(), out + written, &finally_written)) {
102 ldout(cct, 5) << "EVP: EVP_CipherFinal_ex failed" << dendl;
103 return false;
104 }
105
106 // padding is disabled so EVP_CipherFinal_ex should not append anything
107 ceph_assert(finally_written == 0);
108 return (written + finally_written) == static_cast<int>(size);
109 }
110
111
112 /**
113 * Encryption in CBC mode. Chunked to 4K blocks. Offset is used as IV for each 4K block.
114 *
115 *
116 *
117 * A. Encryption
118 * 1. Input is split to 4K chunks + remainder in one, smaller chunk
119 * 2. Each full chunk is encrypted separately with CBC chained mode, with initial IV derived from offset
120 * 3. Last chunk is 16*m + n.
121 * 4. 16*m bytes are encrypted with CBC chained mode, with initial IV derived from offset
122 * 5. Last n bytes are xor-ed with pattern obtained by CBC encryption of
123 * last encrypted 16 byte block <16m-16, 16m-15) with IV = {0}.
124 * 6. (Special case) If m == 0 then last n bytes are xor-ed with pattern
125 * obtained by CBC encryption of {0} with IV derived from offset
126 *
127 * B. Decryption
128 * 1. Input is split to 4K chunks + remainder in one, smaller chunk
129 * 2. Each full chunk is decrypted separately with CBC chained mode, with initial IV derived from offset
130 * 3. Last chunk is 16*m + n.
131 * 4. 16*m bytes are decrypted with CBC chained mode, with initial IV derived from offset
132 * 5. Last n bytes are xor-ed with pattern obtained by CBC ENCRYPTION of
133 * last (still encrypted) 16 byte block <16m-16,16m-15) with IV = {0}
134 * 6. (Special case) If m == 0 then last n bytes are xor-ed with pattern
135 * obtained by CBC ENCRYPTION of {0} with IV derived from offset
136 */
137 class AES_256_CBC : public BlockCrypt {
138 public:
139 static const size_t AES_256_KEYSIZE = 256 / 8;
140 static const size_t AES_256_IVSIZE = 128 / 8;
141 static const size_t CHUNK_SIZE = 4096;
142 private:
143 static const uint8_t IV[AES_256_IVSIZE];
144 CephContext* cct;
145 uint8_t key[AES_256_KEYSIZE];
146 public:
147 explicit AES_256_CBC(CephContext* cct): cct(cct) {
148 }
149 ~AES_256_CBC() {
150 ::ceph::crypto::zeroize_for_security(key, AES_256_KEYSIZE);
151 }
152 bool set_key(const uint8_t* _key, size_t key_size) {
153 if (key_size != AES_256_KEYSIZE) {
154 return false;
155 }
156 memcpy(key, _key, AES_256_KEYSIZE);
157 return true;
158 }
159 size_t get_block_size() {
160 return CHUNK_SIZE;
161 }
162
163 bool cbc_transform(unsigned char* out,
164 const unsigned char* in,
165 const size_t size,
166 const unsigned char (&iv)[AES_256_IVSIZE],
167 const unsigned char (&key)[AES_256_KEYSIZE],
168 bool encrypt)
169 {
170 return evp_sym_transform<AES_256_KEYSIZE, AES_256_IVSIZE>(
171 cct, EVP_aes_256_cbc(), out, in, size, iv, key, encrypt);
172 }
173
174 bool cbc_transform(unsigned char* out,
175 const unsigned char* in,
176 size_t size,
177 off_t stream_offset,
178 const unsigned char (&key)[AES_256_KEYSIZE],
179 bool encrypt)
180 {
181 static std::atomic<bool> failed_to_get_crypto(false);
182 CryptoAccelRef crypto_accel;
183 if (! failed_to_get_crypto.load())
184 {
185 crypto_accel = get_crypto_accel(cct);
186 if (!crypto_accel)
187 failed_to_get_crypto = true;
188 }
189 bool result = true;
190 unsigned char iv[AES_256_IVSIZE];
191 for (size_t offset = 0; result && (offset < size); offset += CHUNK_SIZE) {
192 size_t process_size = offset + CHUNK_SIZE <= size ? CHUNK_SIZE : size - offset;
193 prepare_iv(iv, stream_offset + offset);
194 if (crypto_accel != nullptr) {
195 if (encrypt) {
196 result = crypto_accel->cbc_encrypt(out + offset, in + offset,
197 process_size, iv, key);
198 } else {
199 result = crypto_accel->cbc_decrypt(out + offset, in + offset,
200 process_size, iv, key);
201 }
202 } else {
203 result = cbc_transform(
204 out + offset, in + offset, process_size,
205 iv, key, encrypt);
206 }
207 }
208 return result;
209 }
210
211
212 bool encrypt(bufferlist& input,
213 off_t in_ofs,
214 size_t size,
215 bufferlist& output,
216 off_t stream_offset)
217 {
218 bool result = false;
219 size_t aligned_size = size / AES_256_IVSIZE * AES_256_IVSIZE;
220 size_t unaligned_rest_size = size - aligned_size;
221 output.clear();
222 buffer::ptr buf(aligned_size + AES_256_IVSIZE);
223 unsigned char* buf_raw = reinterpret_cast<unsigned char*>(buf.c_str());
224 const unsigned char* input_raw = reinterpret_cast<const unsigned char*>(input.c_str());
225
226 /* encrypt main bulk of data */
227 result = cbc_transform(buf_raw,
228 input_raw + in_ofs,
229 aligned_size,
230 stream_offset, key, true);
231 if (result && (unaligned_rest_size > 0)) {
232 /* remainder to encrypt */
233 if (aligned_size % CHUNK_SIZE > 0) {
234 /* use last chunk for unaligned part */
235 unsigned char iv[AES_256_IVSIZE] = {0};
236 result = cbc_transform(buf_raw + aligned_size,
237 buf_raw + aligned_size - AES_256_IVSIZE,
238 AES_256_IVSIZE,
239 iv, key, true);
240 } else {
241 /* 0 full blocks in current chunk, use IV as base for unaligned part */
242 unsigned char iv[AES_256_IVSIZE] = {0};
243 unsigned char data[AES_256_IVSIZE];
244 prepare_iv(data, stream_offset + aligned_size);
245 result = cbc_transform(buf_raw + aligned_size,
246 data,
247 AES_256_IVSIZE,
248 iv, key, true);
249 }
250 if (result) {
251 for(size_t i = aligned_size; i < size; i++) {
252 *(buf_raw + i) ^= *(input_raw + in_ofs + i);
253 }
254 }
255 }
256 if (result) {
257 ldout(cct, 25) << "Encrypted " << size << " bytes"<< dendl;
258 buf.set_length(size);
259 output.append(buf);
260 } else {
261 ldout(cct, 5) << "Failed to encrypt" << dendl;
262 }
263 return result;
264 }
265
266
267 bool decrypt(bufferlist& input,
268 off_t in_ofs,
269 size_t size,
270 bufferlist& output,
271 off_t stream_offset)
272 {
273 bool result = false;
274 size_t aligned_size = size / AES_256_IVSIZE * AES_256_IVSIZE;
275 size_t unaligned_rest_size = size - aligned_size;
276 output.clear();
277 buffer::ptr buf(aligned_size + AES_256_IVSIZE);
278 unsigned char* buf_raw = reinterpret_cast<unsigned char*>(buf.c_str());
279 unsigned char* input_raw = reinterpret_cast<unsigned char*>(input.c_str());
280
281 /* decrypt main bulk of data */
282 result = cbc_transform(buf_raw,
283 input_raw + in_ofs,
284 aligned_size,
285 stream_offset, key, false);
286 if (result && unaligned_rest_size > 0) {
287 /* remainder to decrypt */
288 if (aligned_size % CHUNK_SIZE > 0) {
289 /*use last chunk for unaligned part*/
290 unsigned char iv[AES_256_IVSIZE] = {0};
291 result = cbc_transform(buf_raw + aligned_size,
292 input_raw + in_ofs + aligned_size - AES_256_IVSIZE,
293 AES_256_IVSIZE,
294 iv, key, true);
295 } else {
296 /* 0 full blocks in current chunk, use IV as base for unaligned part */
297 unsigned char iv[AES_256_IVSIZE] = {0};
298 unsigned char data[AES_256_IVSIZE];
299 prepare_iv(data, stream_offset + aligned_size);
300 result = cbc_transform(buf_raw + aligned_size,
301 data,
302 AES_256_IVSIZE,
303 iv, key, true);
304 }
305 if (result) {
306 for(size_t i = aligned_size; i < size; i++) {
307 *(buf_raw + i) ^= *(input_raw + in_ofs + i);
308 }
309 }
310 }
311 if (result) {
312 ldout(cct, 25) << "Decrypted " << size << " bytes"<< dendl;
313 buf.set_length(size);
314 output.append(buf);
315 } else {
316 ldout(cct, 5) << "Failed to decrypt" << dendl;
317 }
318 return result;
319 }
320
321
322 void prepare_iv(unsigned char (&iv)[AES_256_IVSIZE], off_t offset) {
323 off_t index = offset / AES_256_IVSIZE;
324 off_t i = AES_256_IVSIZE - 1;
325 unsigned int val;
326 unsigned int carry = 0;
327 while (i>=0) {
328 val = (index & 0xff) + IV[i] + carry;
329 iv[i] = val;
330 carry = val >> 8;
331 index = index >> 8;
332 i--;
333 }
334 }
335 };
336
337
338 std::unique_ptr<BlockCrypt> AES_256_CBC_create(CephContext* cct, const uint8_t* key, size_t len)
339 {
340 auto cbc = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(cct));
341 cbc->set_key(key, AES_256_KEYSIZE);
342 return cbc;
343 }
344
345
346 const uint8_t AES_256_CBC::IV[AES_256_CBC::AES_256_IVSIZE] =
347 { 'a', 'e', 's', '2', '5', '6', 'i', 'v', '_', 'c', 't', 'r', '1', '3', '3', '7' };
348
349
350 bool AES_256_ECB_encrypt(CephContext* cct,
351 const uint8_t* key,
352 size_t key_size,
353 const uint8_t* data_in,
354 uint8_t* data_out,
355 size_t data_size)
356 {
357 if (key_size == AES_256_KEYSIZE) {
358 return evp_sym_transform<AES_256_KEYSIZE, 0 /* no IV in ECB */>(
359 cct, EVP_aes_256_ecb(), data_out, data_in, data_size,
360 nullptr /* no IV in ECB */, key, true /* encrypt */);
361 } else {
362 ldout(cct, 5) << "Key size must be 256 bits long" << dendl;
363 return false;
364 }
365 }
366
367
368 RGWGetObj_BlockDecrypt::RGWGetObj_BlockDecrypt(CephContext* cct,
369 RGWGetObj_Filter* next,
370 std::unique_ptr<BlockCrypt> crypt):
371 RGWGetObj_Filter(next),
372 cct(cct),
373 crypt(std::move(crypt)),
374 enc_begin_skip(0),
375 ofs(0),
376 end(0),
377 cache()
378 {
379 block_size = this->crypt->get_block_size();
380 }
381
382 RGWGetObj_BlockDecrypt::~RGWGetObj_BlockDecrypt() {
383 }
384
385 int RGWGetObj_BlockDecrypt::read_manifest(bufferlist& manifest_bl) {
386 parts_len.clear();
387 RGWObjManifest manifest;
388 if (manifest_bl.length()) {
389 auto miter = manifest_bl.cbegin();
390 try {
391 decode(manifest, miter);
392 } catch (buffer::error& err) {
393 ldout(cct, 0) << "ERROR: couldn't decode manifest" << dendl;
394 return -EIO;
395 }
396 RGWObjManifest::obj_iterator mi;
397 for (mi = manifest.obj_begin(); mi != manifest.obj_end(); ++mi) {
398 if (mi.get_cur_stripe() == 0) {
399 parts_len.push_back(0);
400 }
401 parts_len.back() += mi.get_stripe_size();
402 }
403 if (cct->_conf->subsys.should_gather<ceph_subsys_rgw, 20>()) {
404 for (size_t i = 0; i<parts_len.size(); i++) {
405 ldout(cct, 20) << "Manifest part " << i << ", size=" << parts_len[i] << dendl;
406 }
407 }
408 }
409 return 0;
410 }
411
412 int RGWGetObj_BlockDecrypt::fixup_range(off_t& bl_ofs, off_t& bl_end) {
413 off_t inp_ofs = bl_ofs;
414 off_t inp_end = bl_end;
415 if (parts_len.size() > 0) {
416 off_t in_ofs = bl_ofs;
417 off_t in_end = bl_end;
418
419 size_t i = 0;
420 while (i<parts_len.size() && (in_ofs >= (off_t)parts_len[i])) {
421 in_ofs -= parts_len[i];
422 i++;
423 }
424 //in_ofs is inside block i
425 size_t j = 0;
426 while (j<(parts_len.size() - 1) && (in_end >= (off_t)parts_len[j])) {
427 in_end -= parts_len[j];
428 j++;
429 }
430 //in_end is inside part j, OR j is the last part
431
432 size_t rounded_end = ( in_end & ~(block_size - 1) ) + (block_size - 1);
433 if (rounded_end > parts_len[j]) {
434 rounded_end = parts_len[j] - 1;
435 }
436
437 enc_begin_skip = in_ofs & (block_size - 1);
438 ofs = bl_ofs - enc_begin_skip;
439 end = bl_end;
440 bl_end += rounded_end - in_end;
441 bl_ofs = std::min(bl_ofs - enc_begin_skip, bl_end);
442 }
443 else
444 {
445 enc_begin_skip = bl_ofs & (block_size - 1);
446 ofs = bl_ofs & ~(block_size - 1);
447 end = bl_end;
448 bl_ofs = bl_ofs & ~(block_size - 1);
449 bl_end = ( bl_end & ~(block_size - 1) ) + (block_size - 1);
450 }
451 ldout(cct, 20) << "fixup_range [" << inp_ofs << "," << inp_end
452 << "] => [" << bl_ofs << "," << bl_end << "]" << dendl;
453 return 0;
454 }
455
456 int RGWGetObj_BlockDecrypt::process(bufferlist& in, size_t part_ofs, size_t size)
457 {
458 bufferlist data;
459 if (!crypt->decrypt(in, 0, size, data, part_ofs)) {
460 return -ERR_INTERNAL_ERROR;
461 }
462 off_t send_size = size - enc_begin_skip;
463 if (ofs + enc_begin_skip + send_size > end + 1) {
464 send_size = end + 1 - ofs - enc_begin_skip;
465 }
466 int res = next->handle_data(data, enc_begin_skip, send_size);
467 enc_begin_skip = 0;
468 ofs += size;
469 in.splice(0, size);
470 return res;
471 }
472
473 int RGWGetObj_BlockDecrypt::handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) {
474 ldout(cct, 25) << "Decrypt " << bl_len << " bytes" << dendl;
475 bl.begin(bl_ofs).copy(bl_len, cache);
476
477 int res = 0;
478 size_t part_ofs = ofs;
479 for (size_t part : parts_len) {
480 if (part_ofs >= part) {
481 part_ofs -= part;
482 } else if (part_ofs + cache.length() >= part) {
483 // flush data up to part boundaries, aligned or not
484 res = process(cache, part_ofs, part - part_ofs);
485 if (res < 0) {
486 return res;
487 }
488 part_ofs = 0;
489 } else {
490 break;
491 }
492 }
493 // write up to block boundaries, aligned only
494 off_t aligned_size = cache.length() & ~(block_size - 1);
495 if (aligned_size > 0) {
496 res = process(cache, part_ofs, aligned_size);
497 }
498 return res;
499 }
500
501 /**
502 * flush remainder of data to output
503 */
504 int RGWGetObj_BlockDecrypt::flush() {
505 ldout(cct, 25) << "Decrypt flushing " << cache.length() << " bytes" << dendl;
506 int res = 0;
507 size_t part_ofs = ofs;
508 for (size_t part : parts_len) {
509 if (part_ofs >= part) {
510 part_ofs -= part;
511 } else if (part_ofs + cache.length() >= part) {
512 // flush data up to part boundaries, aligned or not
513 res = process(cache, part_ofs, part - part_ofs);
514 if (res < 0) {
515 return res;
516 }
517 part_ofs = 0;
518 } else {
519 break;
520 }
521 }
522 // flush up to block boundaries, aligned or not
523 if (cache.length() > 0) {
524 res = process(cache, part_ofs, cache.length());
525 }
526 return res;
527 }
528
529 RGWPutObj_BlockEncrypt::RGWPutObj_BlockEncrypt(CephContext* cct,
530 rgw::putobj::DataProcessor *next,
531 std::unique_ptr<BlockCrypt> crypt)
532 : Pipe(next),
533 cct(cct),
534 crypt(std::move(crypt)),
535 block_size(this->crypt->get_block_size())
536 {
537 }
538
539 int RGWPutObj_BlockEncrypt::process(bufferlist&& data, uint64_t logical_offset)
540 {
541 ldout(cct, 25) << "Encrypt " << data.length() << " bytes" << dendl;
542
543 // adjust logical offset to beginning of cached data
544 ceph_assert(logical_offset >= cache.length());
545 logical_offset -= cache.length();
546
547 const bool flush = (data.length() == 0);
548 cache.claim_append(data);
549
550 uint64_t proc_size = cache.length() & ~(block_size - 1);
551 if (flush) {
552 proc_size = cache.length();
553 }
554 if (proc_size > 0) {
555 bufferlist in, out;
556 cache.splice(0, proc_size, &in);
557 if (!crypt->encrypt(in, 0, proc_size, out, logical_offset)) {
558 return -ERR_INTERNAL_ERROR;
559 }
560 int r = Pipe::process(std::move(out), logical_offset);
561 logical_offset += proc_size;
562 if (r < 0)
563 return r;
564 }
565
566 if (flush) {
567 /*replicate 0-sized handle_data*/
568 return Pipe::process({}, logical_offset);
569 }
570 return 0;
571 }
572
573
574 std::string create_random_key_selector(CephContext * const cct) {
575 char random[AES_256_KEYSIZE];
576 cct->random()->get_bytes(&random[0], sizeof(random));
577 return std::string(random, sizeof(random));
578 }
579
580 static inline void set_attr(map<string, bufferlist>& attrs,
581 const char* key,
582 boost::string_view value)
583 {
584 bufferlist bl;
585 bl.append(value.data(), value.size());
586 attrs[key] = std::move(bl);
587 }
588
589 static inline std::string get_str_attribute(map<string, bufferlist>& attrs,
590 const char *name)
591 {
592 auto iter = attrs.find(name);
593 if (iter == attrs.end()) {
594 return {};
595 }
596 return iter->second.to_str();
597 }
598
599 typedef enum {
600 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM=0,
601 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY,
602 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5,
603 X_AMZ_SERVER_SIDE_ENCRYPTION,
604 X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID,
605 X_AMZ_SERVER_SIDE_ENCRYPTION_LAST
606 } crypt_option_e;
607
608 typedef struct {
609 const char* http_header_name;
610 const std::string post_part_name;
611 } crypt_option_names;
612
613 static const crypt_option_names crypt_options[] = {
614 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", "x-amz-server-side-encryption-customer-algorithm"},
615 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", "x-amz-server-side-encryption-customer-key"},
616 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "x-amz-server-side-encryption-customer-key-md5"},
617 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION", "x-amz-server-side-encryption"},
618 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID", "x-amz-server-side-encryption-aws-kms-key-id"},
619 };
620
621 static boost::string_view get_crypt_attribute(
622 const RGWEnv* env,
623 std::map<std::string,
624 RGWPostObj_ObjStore::post_form_part,
625 const ltstr_nocase>* parts,
626 crypt_option_e option)
627 {
628 static_assert(
629 X_AMZ_SERVER_SIDE_ENCRYPTION_LAST == sizeof(crypt_options)/sizeof(*crypt_options),
630 "Missing items in crypt_options");
631 if (parts != nullptr) {
632 auto iter
633 = parts->find(crypt_options[option].post_part_name);
634 if (iter == parts->end())
635 return boost::string_view();
636 bufferlist& data = iter->second.data;
637 boost::string_view str = boost::string_view(data.c_str(), data.length());
638 return rgw_trim_whitespace(str);
639 } else {
640 const char* hdr = env->get(crypt_options[option].http_header_name, nullptr);
641 if (hdr != nullptr) {
642 return boost::string_view(hdr);
643 } else {
644 return boost::string_view();
645 }
646 }
647 }
648
649
650 int rgw_s3_prepare_encrypt(struct req_state* s,
651 std::map<std::string, ceph::bufferlist>& attrs,
652 std::map<std::string,
653 RGWPostObj_ObjStore::post_form_part,
654 const ltstr_nocase>* parts,
655 std::unique_ptr<BlockCrypt>* block_crypt,
656 std::map<std::string, std::string>& crypt_http_responses)
657 {
658 int res = 0;
659 crypt_http_responses.clear();
660 {
661 boost::string_view req_sse_ca =
662 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM);
663 if (! req_sse_ca.empty()) {
664 if (req_sse_ca != "AES256") {
665 ldout(s->cct, 5) << "ERROR: Invalid value for header "
666 << "x-amz-server-side-encryption-customer-algorithm"
667 << dendl;
668 s->err.message = "The requested encryption algorithm is not valid, must be AES256.";
669 return -ERR_INVALID_ENCRYPTION_ALGORITHM;
670 }
671 if (s->cct->_conf->rgw_crypt_require_ssl &&
672 !rgw_transport_is_secure(s->cct, *s->info.env)) {
673 ldout(s->cct, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl;
674 return -ERR_INVALID_REQUEST;
675 }
676
677 std::string key_bin;
678 try {
679 key_bin = from_base64(
680 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY) );
681 } catch (...) {
682 ldout(s->cct, 5) << "ERROR: rgw_s3_prepare_encrypt invalid encryption "
683 << "key which contains character that is not base64 encoded."
684 << dendl;
685 s->err.message = "Requests specifying Server Side Encryption with Customer "
686 "provided keys must provide an appropriate secret key.";
687 return -EINVAL;
688 }
689
690 if (key_bin.size() != AES_256_CBC::AES_256_KEYSIZE) {
691 ldout(s->cct, 5) << "ERROR: invalid encryption key size" << dendl;
692 s->err.message = "Requests specifying Server Side Encryption with Customer "
693 "provided keys must provide an appropriate secret key.";
694 return -EINVAL;
695 }
696
697 boost::string_view keymd5 =
698 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5);
699
700 std::string keymd5_bin;
701 try {
702 keymd5_bin = from_base64(keymd5);
703 } catch (...) {
704 ldout(s->cct, 5) << "ERROR: rgw_s3_prepare_encrypt invalid encryption key "
705 << "md5 which contains character that is not base64 encoded."
706 << dendl;
707 s->err.message = "Requests specifying Server Side Encryption with Customer "
708 "provided keys must provide an appropriate secret key md5.";
709 return -EINVAL;
710 }
711
712 if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
713 ldout(s->cct, 5) << "ERROR: Invalid key md5 size" << dendl;
714 s->err.message = "Requests specifying Server Side Encryption with Customer "
715 "provided keys must provide an appropriate secret key md5.";
716 return -EINVAL;
717 }
718
719 MD5 key_hash;
720 unsigned char key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE];
721 key_hash.Update(reinterpret_cast<const unsigned char*>(key_bin.c_str()), key_bin.size());
722 key_hash.Final(key_hash_res);
723
724 if (memcmp(key_hash_res, keymd5_bin.c_str(), CEPH_CRYPTO_MD5_DIGESTSIZE) != 0) {
725 ldout(s->cct, 5) << "ERROR: Invalid key md5 hash" << dendl;
726 s->err.message = "The calculated MD5 hash of the key did not match the hash that was provided.";
727 return -EINVAL;
728 }
729
730 set_attr(attrs, RGW_ATTR_CRYPT_MODE, "SSE-C-AES256");
731 set_attr(attrs, RGW_ATTR_CRYPT_KEYMD5, keymd5_bin);
732
733 if (block_crypt) {
734 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
735 aes->set_key(reinterpret_cast<const uint8_t*>(key_bin.c_str()), AES_256_KEYSIZE);
736 *block_crypt = std::move(aes);
737 }
738
739 crypt_http_responses["x-amz-server-side-encryption-customer-algorithm"] = "AES256";
740 crypt_http_responses["x-amz-server-side-encryption-customer-key-MD5"] = keymd5.to_string();
741 return 0;
742 } else {
743 boost::string_view customer_key =
744 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY);
745 if (!customer_key.empty()) {
746 ldout(s->cct, 5) << "ERROR: SSE-C encryption request is missing the header "
747 << "x-amz-server-side-encryption-customer-algorithm"
748 << dendl;
749 s->err.message = "Requests specifying Server Side Encryption with Customer "
750 "provided keys must provide a valid encryption algorithm.";
751 return -EINVAL;
752 }
753
754 boost::string_view customer_key_md5 =
755 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5);
756 if (!customer_key_md5.empty()) {
757 ldout(s->cct, 5) << "ERROR: SSE-C encryption request is missing the header "
758 << "x-amz-server-side-encryption-customer-algorithm"
759 << dendl;
760 s->err.message = "Requests specifying Server Side Encryption with Customer "
761 "provided keys must provide a valid encryption algorithm.";
762 return -EINVAL;
763 }
764 }
765
766 /* AMAZON server side encryption with KMS (key management service) */
767 boost::string_view req_sse =
768 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION);
769 if (! req_sse.empty()) {
770
771 if (s->cct->_conf->rgw_crypt_require_ssl &&
772 !rgw_transport_is_secure(s->cct, *s->info.env)) {
773 ldout(s->cct, 5) << "ERROR: insecure request, rgw_crypt_require_ssl is set" << dendl;
774 return -ERR_INVALID_REQUEST;
775 }
776
777 if (req_sse == "aws:kms") {
778 boost::string_view key_id =
779 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID);
780 if (key_id.empty()) {
781 ldout(s->cct, 5) << "ERROR: not provide a valid key id" << dendl;
782 s->err.message = "Server Side Encryption with KMS managed key requires "
783 "HTTP header x-amz-server-side-encryption-aws-kms-key-id";
784 return -ERR_INVALID_ACCESS_KEY;
785 }
786 /* try to retrieve actual key */
787 std::string key_selector = create_random_key_selector(s->cct);
788 std::string actual_key;
789 res = get_actual_key_from_kms(s->cct, key_id, key_selector, actual_key);
790 if (res != 0) {
791 ldout(s->cct, 5) << "ERROR: failed to retrieve actual key from key_id: " << key_id << dendl;
792 s->err.message = "Failed to retrieve the actual key, kms-keyid: " + key_id.to_string();
793 return res;
794 }
795 if (actual_key.size() != AES_256_KEYSIZE) {
796 ldout(s->cct, 5) << "ERROR: key obtained from key_id:" <<
797 key_id << " is not 256 bit size" << dendl;
798 s->err.message = "KMS provided an invalid key for the given kms-keyid.";
799 return -ERR_INVALID_ACCESS_KEY;
800 }
801 set_attr(attrs, RGW_ATTR_CRYPT_MODE, "SSE-KMS");
802 set_attr(attrs, RGW_ATTR_CRYPT_KEYID, key_id);
803 set_attr(attrs, RGW_ATTR_CRYPT_KEYSEL, key_selector);
804
805 if (block_crypt) {
806 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
807 aes->set_key(reinterpret_cast<const uint8_t*>(actual_key.c_str()), AES_256_KEYSIZE);
808 *block_crypt = std::move(aes);
809 }
810 actual_key.replace(0, actual_key.length(), actual_key.length(), '\000');
811
812 crypt_http_responses["x-amz-server-side-encryption"] = "aws:kms";
813 crypt_http_responses["x-amz-server-side-encryption-aws-kms-key-id"] = key_id.to_string();
814 return 0;
815 } else if (req_sse == "AES256") {
816 /* if a default encryption key was provided, we will use it for SSE-S3 */
817 } else {
818 ldout(s->cct, 5) << "ERROR: Invalid value for header x-amz-server-side-encryption"
819 << dendl;
820 s->err.message = "Server Side Encryption with KMS managed key requires "
821 "HTTP header x-amz-server-side-encryption : aws:kms or AES256";
822 return -EINVAL;
823 }
824 } else {
825 /* x-amz-server-side-encryption not present or empty */
826 boost::string_view key_id =
827 get_crypt_attribute(s->info.env, parts,
828 X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID);
829 if (!key_id.empty()) {
830 ldout(s->cct, 5) << "ERROR: SSE-KMS encryption request is missing the header "
831 << "x-amz-server-side-encryption"
832 << dendl;
833 s->err.message = "Server Side Encryption with KMS managed key requires "
834 "HTTP header x-amz-server-side-encryption : aws:kms";
835 return -EINVAL;
836 }
837 }
838
839 /* no other encryption mode, check if default encryption is selected */
840 if (s->cct->_conf->rgw_crypt_default_encryption_key != "") {
841 std::string master_encryption_key;
842 try {
843 master_encryption_key = from_base64(s->cct->_conf->rgw_crypt_default_encryption_key);
844 } catch (...) {
845 ldout(s->cct, 5) << "ERROR: rgw_s3_prepare_encrypt invalid default encryption key "
846 << "which contains character that is not base64 encoded."
847 << dendl;
848 s->err.message = "Requests specifying Server Side Encryption with Customer "
849 "provided keys must provide an appropriate secret key.";
850 return -EINVAL;
851 }
852
853 if (master_encryption_key.size() != 256 / 8) {
854 ldout(s->cct, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl;
855 /* not an error to return; missing encryption does not inhibit processing */
856 return 0;
857 }
858
859 set_attr(attrs, RGW_ATTR_CRYPT_MODE, "RGW-AUTO");
860 std::string key_selector = create_random_key_selector(s->cct);
861 set_attr(attrs, RGW_ATTR_CRYPT_KEYSEL, key_selector);
862
863 uint8_t actual_key[AES_256_KEYSIZE];
864 if (AES_256_ECB_encrypt(s->cct,
865 reinterpret_cast<const uint8_t*>(master_encryption_key.c_str()), AES_256_KEYSIZE,
866 reinterpret_cast<const uint8_t*>(key_selector.c_str()),
867 actual_key, AES_256_KEYSIZE) != true) {
868 ::ceph::crypto::zeroize_for_security(actual_key, sizeof(actual_key));
869 return -EIO;
870 }
871 if (block_crypt) {
872 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
873 aes->set_key(reinterpret_cast<const uint8_t*>(actual_key), AES_256_KEYSIZE);
874 *block_crypt = std::move(aes);
875 }
876 ::ceph::crypto::zeroize_for_security(actual_key, sizeof(actual_key));
877 return 0;
878 }
879 }
880 /*no encryption*/
881 return 0;
882 }
883
884
885 int rgw_s3_prepare_decrypt(struct req_state* s,
886 map<string, bufferlist>& attrs,
887 std::unique_ptr<BlockCrypt>* block_crypt,
888 std::map<std::string, std::string>& crypt_http_responses)
889 {
890 int res = 0;
891 std::string stored_mode = get_str_attribute(attrs, RGW_ATTR_CRYPT_MODE);
892 ldout(s->cct, 15) << "Encryption mode: " << stored_mode << dendl;
893
894 const char *req_sse = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION", NULL);
895 if (nullptr != req_sse && (s->op == OP_GET || s->op == OP_HEAD)) {
896 return -ERR_INVALID_REQUEST;
897 }
898
899 if (stored_mode == "SSE-C-AES256") {
900 if (s->cct->_conf->rgw_crypt_require_ssl &&
901 !rgw_transport_is_secure(s->cct, *s->info.env)) {
902 ldout(s->cct, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl;
903 return -ERR_INVALID_REQUEST;
904 }
905 const char *req_cust_alg =
906 s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", NULL);
907
908 if (nullptr == req_cust_alg) {
909 ldout(s->cct, 5) << "ERROR: Request for SSE-C encrypted object missing "
910 << "x-amz-server-side-encryption-customer-algorithm"
911 << dendl;
912 s->err.message = "Requests specifying Server Side Encryption with Customer "
913 "provided keys must provide a valid encryption algorithm.";
914 return -EINVAL;
915 } else if (strcmp(req_cust_alg, "AES256") != 0) {
916 ldout(s->cct, 5) << "ERROR: The requested encryption algorithm is not valid, must be AES256." << dendl;
917 s->err.message = "The requested encryption algorithm is not valid, must be AES256.";
918 return -ERR_INVALID_ENCRYPTION_ALGORITHM;
919 }
920
921 std::string key_bin;
922 try {
923 key_bin = from_base64(s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", ""));
924 } catch (...) {
925 ldout(s->cct, 5) << "ERROR: rgw_s3_prepare_decrypt invalid encryption key "
926 << "which contains character that is not base64 encoded."
927 << dendl;
928 s->err.message = "Requests specifying Server Side Encryption with Customer "
929 "provided keys must provide an appropriate secret key.";
930 return -EINVAL;
931 }
932
933 if (key_bin.size() != AES_256_CBC::AES_256_KEYSIZE) {
934 ldout(s->cct, 5) << "ERROR: Invalid encryption key size" << dendl;
935 s->err.message = "Requests specifying Server Side Encryption with Customer "
936 "provided keys must provide an appropriate secret key.";
937 return -EINVAL;
938 }
939
940 std::string keymd5 =
941 s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "");
942 std::string keymd5_bin;
943 try {
944 keymd5_bin = from_base64(keymd5);
945 } catch (...) {
946 ldout(s->cct, 5) << "ERROR: rgw_s3_prepare_decrypt invalid encryption key md5 "
947 << "which contains character that is not base64 encoded."
948 << dendl;
949 s->err.message = "Requests specifying Server Side Encryption with Customer "
950 "provided keys must provide an appropriate secret key md5.";
951 return -EINVAL;
952 }
953
954
955 if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
956 ldout(s->cct, 5) << "ERROR: Invalid key md5 size " << dendl;
957 s->err.message = "Requests specifying Server Side Encryption with Customer "
958 "provided keys must provide an appropriate secret key md5.";
959 return -EINVAL;
960 }
961
962 MD5 key_hash;
963 uint8_t key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE];
964 key_hash.Update(reinterpret_cast<const unsigned char*>(key_bin.c_str()), key_bin.size());
965 key_hash.Final(key_hash_res);
966
967 if ((memcmp(key_hash_res, keymd5_bin.c_str(), CEPH_CRYPTO_MD5_DIGESTSIZE) != 0) ||
968 (get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYMD5) != keymd5_bin)) {
969 s->err.message = "The calculated MD5 hash of the key did not match the hash that was provided.";
970 return -EINVAL;
971 }
972 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
973 aes->set_key(reinterpret_cast<const uint8_t*>(key_bin.c_str()), AES_256_CBC::AES_256_KEYSIZE);
974 if (block_crypt) *block_crypt = std::move(aes);
975
976 crypt_http_responses["x-amz-server-side-encryption-customer-algorithm"] = "AES256";
977 crypt_http_responses["x-amz-server-side-encryption-customer-key-MD5"] = keymd5;
978 return 0;
979 }
980
981 if (stored_mode == "SSE-KMS") {
982 if (s->cct->_conf->rgw_crypt_require_ssl &&
983 !rgw_transport_is_secure(s->cct, *s->info.env)) {
984 ldout(s->cct, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl;
985 return -ERR_INVALID_REQUEST;
986 }
987 /* try to retrieve actual key */
988 std::string key_id = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYID);
989 std::string key_selector = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYSEL);
990 std::string actual_key;
991 res = get_actual_key_from_kms(s->cct, key_id, key_selector, actual_key);
992 if (res != 0) {
993 ldout(s->cct, 10) << "ERROR: failed to retrieve actual key from key_id: " << key_id << dendl;
994 s->err.message = "Failed to retrieve the actual key, kms-keyid: " + key_id;
995 return res;
996 }
997 if (actual_key.size() != AES_256_KEYSIZE) {
998 ldout(s->cct, 0) << "ERROR: key obtained from key_id:" <<
999 key_id << " is not 256 bit size" << dendl;
1000 s->err.message = "KMS provided an invalid key for the given kms-keyid.";
1001 return -ERR_INVALID_ACCESS_KEY;
1002 }
1003
1004 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
1005 aes->set_key(reinterpret_cast<const uint8_t*>(actual_key.c_str()), AES_256_KEYSIZE);
1006 actual_key.replace(0, actual_key.length(), actual_key.length(), '\000');
1007 if (block_crypt) *block_crypt = std::move(aes);
1008
1009 crypt_http_responses["x-amz-server-side-encryption"] = "aws:kms";
1010 crypt_http_responses["x-amz-server-side-encryption-aws-kms-key-id"] = key_id;
1011 return 0;
1012 }
1013
1014 if (stored_mode == "RGW-AUTO") {
1015 std::string master_encryption_key;
1016 try {
1017 master_encryption_key = from_base64(std::string(s->cct->_conf->rgw_crypt_default_encryption_key));
1018 } catch (...) {
1019 ldout(s->cct, 5) << "ERROR: rgw_s3_prepare_decrypt invalid default encryption key "
1020 << "which contains character that is not base64 encoded."
1021 << dendl;
1022 s->err.message = "The default encryption key is not valid base64.";
1023 return -EINVAL;
1024 }
1025
1026 if (master_encryption_key.size() != 256 / 8) {
1027 ldout(s->cct, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl;
1028 return -EIO;
1029 }
1030 std::string attr_key_selector = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYSEL);
1031 if (attr_key_selector.size() != AES_256_CBC::AES_256_KEYSIZE) {
1032 ldout(s->cct, 0) << "ERROR: missing or invalid " RGW_ATTR_CRYPT_KEYSEL << dendl;
1033 return -EIO;
1034 }
1035 uint8_t actual_key[AES_256_KEYSIZE];
1036 if (AES_256_ECB_encrypt(s->cct,
1037 reinterpret_cast<const uint8_t*>(master_encryption_key.c_str()),
1038 AES_256_KEYSIZE,
1039 reinterpret_cast<const uint8_t*>(attr_key_selector.c_str()),
1040 actual_key, AES_256_KEYSIZE) != true) {
1041 ::ceph::crypto::zeroize_for_security(actual_key, sizeof(actual_key));
1042 return -EIO;
1043 }
1044 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
1045 aes->set_key(actual_key, AES_256_KEYSIZE);
1046 ::ceph::crypto::zeroize_for_security(actual_key, sizeof(actual_key));
1047 if (block_crypt) *block_crypt = std::move(aes);
1048 return 0;
1049 }
1050 /*no decryption*/
1051 return 0;
1052 }