]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_crypt.cc
update sources to ceph Nautilus 14.2.1
[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
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 <rgw/rgw_keystone.h>
16 #include "include/str_map.h"
17 #include "crypto/crypto_accel.h"
18 #include "crypto/crypto_plugin.h"
19 #ifdef USE_NSS
20 # include <nspr.h>
21 # include <nss.h>
22 # include <pk11pub.h>
23 #endif
24
25 #define dout_context g_ceph_context
26 #define dout_subsys ceph_subsys_rgw
27
28 using namespace rgw;
29
30 /**
31 * Encryption in CTR mode. offset is used as IV for each block.
32 */
33 class AES_256_CTR : public BlockCrypt {
34 public:
35 static const size_t AES_256_KEYSIZE = 256 / 8;
36 static const size_t AES_256_IVSIZE = 128 / 8;
37 private:
38 static const uint8_t IV[AES_256_IVSIZE];
39 CephContext* cct;
40 uint8_t key[AES_256_KEYSIZE];
41 public:
42 explicit AES_256_CTR(CephContext* cct): cct(cct) {
43 }
44 ~AES_256_CTR() {
45 memset(key, 0, AES_256_KEYSIZE);
46 }
47 bool set_key(const uint8_t* _key, size_t key_size) {
48 if (key_size != AES_256_KEYSIZE) {
49 return false;
50 }
51 memcpy(key, _key, AES_256_KEYSIZE);
52 return true;
53 }
54 size_t get_block_size() {
55 return AES_256_IVSIZE;
56 }
57
58 #ifdef USE_NSS
59
60 bool encrypt(bufferlist& input, off_t in_ofs, size_t size, bufferlist& output, off_t stream_offset)
61 {
62 bool result = false;
63 PK11SlotInfo *slot;
64 SECItem keyItem;
65 PK11SymKey *symkey;
66 CK_AES_CTR_PARAMS ctr_params = {0};
67 SECItem ivItem;
68 SECItem *param;
69 SECStatus ret;
70 PK11Context *ectx;
71 int written;
72 unsigned int written2;
73
74 slot = PK11_GetBestSlot(CKM_AES_CTR, NULL);
75 if (slot) {
76 keyItem.type = siBuffer;
77 keyItem.data = key;
78 keyItem.len = AES_256_KEYSIZE;
79
80 symkey = PK11_ImportSymKey(slot, CKM_AES_CTR, PK11_OriginUnwrap, CKA_UNWRAP, &keyItem, NULL);
81 if (symkey) {
82 static_assert(sizeof(ctr_params.cb) >= AES_256_IVSIZE, "Must fit counter");
83 ctr_params.ulCounterBits = 128;
84 prepare_iv(reinterpret_cast<unsigned char*>(&ctr_params.cb), stream_offset);
85
86 ivItem.type = siBuffer;
87 ivItem.data = (unsigned char*)&ctr_params;
88 ivItem.len = sizeof(ctr_params);
89
90 param = PK11_ParamFromIV(CKM_AES_CTR, &ivItem);
91 if (param) {
92 ectx = PK11_CreateContextBySymKey(CKM_AES_CTR, CKA_ENCRYPT, symkey, param);
93 if (ectx) {
94 buffer::ptr buf((size + AES_256_KEYSIZE - 1) / AES_256_KEYSIZE * AES_256_KEYSIZE);
95 ret = PK11_CipherOp(ectx,
96 (unsigned char*)buf.c_str(), &written, buf.length(),
97 (unsigned char*)input.c_str() + in_ofs, size);
98 if (ret == SECSuccess) {
99 ret = PK11_DigestFinal(ectx,
100 (unsigned char*)buf.c_str() + written, &written2,
101 buf.length() - written);
102 if (ret == SECSuccess) {
103 buf.set_length(written + written2);
104 output.append(buf);
105 result = true;
106 }
107 }
108 PK11_DestroyContext(ectx, PR_TRUE);
109 }
110 SECITEM_FreeItem(param, PR_TRUE);
111 }
112 PK11_FreeSymKey(symkey);
113 }
114 PK11_FreeSlot(slot);
115 }
116 if (result == false) {
117 ldout(cct, 5) << "Failed to perform AES-CTR encryption: " << PR_GetError() << dendl;
118 }
119 return result;
120 }
121
122 #else
123 # error "No supported crypto implementation found."
124 #endif
125 /* in CTR encrypt is the same as decrypt */
126 bool decrypt(bufferlist& input, off_t in_ofs, size_t size, bufferlist& output, off_t stream_offset) {
127 return encrypt(input, in_ofs, size, output, stream_offset);
128 }
129
130 void prepare_iv(unsigned char iv[AES_256_IVSIZE], off_t offset) {
131 off_t index = offset / AES_256_IVSIZE;
132 off_t i = AES_256_IVSIZE - 1;
133 unsigned int val;
134 unsigned int carry = 0;
135 while (i>=0) {
136 val = (index & 0xff) + IV[i] + carry;
137 iv[i] = val;
138 carry = val >> 8;
139 index = index >> 8;
140 i--;
141 }
142 }
143 };
144
145 const uint8_t AES_256_CTR::IV[AES_256_CTR::AES_256_IVSIZE] =
146 { 'a', 'e', 's', '2', '5', '6', 'i', 'v', '_', 'c', 't', 'r', '1', '3', '3', '7' };
147
148
149 CryptoAccelRef get_crypto_accel(CephContext *cct)
150 {
151 CryptoAccelRef ca_impl = nullptr;
152 stringstream ss;
153 PluginRegistry *reg = cct->get_plugin_registry();
154 string crypto_accel_type = cct->_conf->plugin_crypto_accelerator;
155
156 CryptoPlugin *factory = dynamic_cast<CryptoPlugin*>(reg->get_with_load("crypto", crypto_accel_type));
157 if (factory == nullptr) {
158 lderr(cct) << __func__ << " cannot load crypto accelerator of type " << crypto_accel_type << dendl;
159 return nullptr;
160 }
161 int err = factory->factory(&ca_impl, &ss);
162 if (err) {
163 lderr(cct) << __func__ << " factory return error " << err <<
164 " with description: " << ss.str() << dendl;
165 }
166 return ca_impl;
167 }
168
169
170 /**
171 * Encryption in CBC mode. Chunked to 4K blocks. Offset is used as IV for each 4K block.
172 *
173 *
174 *
175 * A. Encryption
176 * 1. Input is split to 4K chunks + remainder in one, smaller chunk
177 * 2. Each full chunk is encrypted separately with CBC chained mode, with initial IV derived from offset
178 * 3. Last chunk is 16*m + n.
179 * 4. 16*m bytes are encrypted with CBC chained mode, with initial IV derived from offset
180 * 5. Last n bytes are xor-ed with pattern obtained by CBC encryption of
181 * last encrypted 16 byte block <16m-16, 16m-15) with IV = {0}.
182 * 6. (Special case) If m == 0 then last n bytes are xor-ed with pattern
183 * obtained by CBC encryption of {0} with IV derived from offset
184 *
185 * B. Decryption
186 * 1. Input is split to 4K chunks + remainder in one, smaller chunk
187 * 2. Each full chunk is decrypted separately with CBC chained mode, with initial IV derived from offset
188 * 3. Last chunk is 16*m + n.
189 * 4. 16*m bytes are decrypted with CBC chained mode, with initial IV derived from offset
190 * 5. Last n bytes are xor-ed with pattern obtained by CBC ENCRYPTION of
191 * last (still encrypted) 16 byte block <16m-16,16m-15) with IV = {0}
192 * 6. (Special case) If m == 0 then last n bytes are xor-ed with pattern
193 * obtained by CBC ENCRYPTION of {0} with IV derived from offset
194 */
195 class AES_256_CBC : public BlockCrypt {
196 public:
197 static const size_t AES_256_KEYSIZE = 256 / 8;
198 static const size_t AES_256_IVSIZE = 128 / 8;
199 static const size_t CHUNK_SIZE = 4096;
200 private:
201 static const uint8_t IV[AES_256_IVSIZE];
202 CephContext* cct;
203 uint8_t key[AES_256_KEYSIZE];
204 public:
205 explicit AES_256_CBC(CephContext* cct): cct(cct) {
206 }
207 ~AES_256_CBC() {
208 memset(key, 0, AES_256_KEYSIZE);
209 }
210 bool set_key(const uint8_t* _key, size_t key_size) {
211 if (key_size != AES_256_KEYSIZE) {
212 return false;
213 }
214 memcpy(key, _key, AES_256_KEYSIZE);
215 return true;
216 }
217 size_t get_block_size() {
218 return CHUNK_SIZE;
219 }
220
221 #ifdef USE_NSS
222
223 bool cbc_transform(unsigned char* out,
224 const unsigned char* in,
225 size_t size,
226 const unsigned char (&iv)[AES_256_IVSIZE],
227 const unsigned char (&key)[AES_256_KEYSIZE],
228 bool encrypt)
229 {
230 bool result = false;
231 PK11SlotInfo *slot;
232 SECItem keyItem;
233 PK11SymKey *symkey;
234 CK_AES_CBC_ENCRYPT_DATA_PARAMS ctr_params = {0};
235 SECItem ivItem;
236 SECItem *param;
237 SECStatus ret;
238 PK11Context *ectx;
239 int written;
240
241 slot = PK11_GetBestSlot(CKM_AES_CBC, NULL);
242 if (slot) {
243 keyItem.type = siBuffer;
244 keyItem.data = const_cast<unsigned char*>(&key[0]);
245 keyItem.len = AES_256_KEYSIZE;
246 symkey = PK11_ImportSymKey(slot, CKM_AES_CBC, PK11_OriginUnwrap, CKA_UNWRAP, &keyItem, NULL);
247 if (symkey) {
248 memcpy(ctr_params.iv, iv, AES_256_IVSIZE);
249 ivItem.type = siBuffer;
250 ivItem.data = (unsigned char*)&ctr_params;
251 ivItem.len = sizeof(ctr_params);
252
253 param = PK11_ParamFromIV(CKM_AES_CBC, &ivItem);
254 if (param) {
255 ectx = PK11_CreateContextBySymKey(CKM_AES_CBC, encrypt?CKA_ENCRYPT:CKA_DECRYPT, symkey, param);
256 if (ectx) {
257 ret = PK11_CipherOp(ectx,
258 out, &written, size,
259 in, size);
260 if ((ret == SECSuccess) && (written == (int)size)) {
261 result = true;
262 }
263 PK11_DestroyContext(ectx, PR_TRUE);
264 }
265 SECITEM_FreeItem(param, PR_TRUE);
266 }
267 PK11_FreeSymKey(symkey);
268 }
269 PK11_FreeSlot(slot);
270 }
271 if (result == false) {
272 ldout(cct, 5) << "Failed to perform AES-CBC encryption: " << PR_GetError() << dendl;
273 }
274 return result;
275 }
276
277 #else
278 # error "No supported crypto implementation found."
279 #endif
280
281 bool cbc_transform(unsigned char* out,
282 const unsigned char* in,
283 size_t size,
284 off_t stream_offset,
285 const unsigned char (&key)[AES_256_KEYSIZE],
286 bool encrypt)
287 {
288 static std::atomic<bool> failed_to_get_crypto(false);
289 CryptoAccelRef crypto_accel;
290 if (! failed_to_get_crypto.load())
291 {
292 crypto_accel = get_crypto_accel(cct);
293 if (!crypto_accel)
294 failed_to_get_crypto = true;
295 }
296 bool result = true;
297 unsigned char iv[AES_256_IVSIZE];
298 for (size_t offset = 0; result && (offset < size); offset += CHUNK_SIZE) {
299 size_t process_size = offset + CHUNK_SIZE <= size ? CHUNK_SIZE : size - offset;
300 prepare_iv(iv, stream_offset + offset);
301 if (crypto_accel != nullptr) {
302 if (encrypt) {
303 result = crypto_accel->cbc_encrypt(out + offset, in + offset,
304 process_size, iv, key);
305 } else {
306 result = crypto_accel->cbc_decrypt(out + offset, in + offset,
307 process_size, iv, key);
308 }
309 } else {
310 result = cbc_transform(
311 out + offset, in + offset, process_size,
312 iv, key, encrypt);
313 }
314 }
315 return result;
316 }
317
318
319 bool encrypt(bufferlist& input,
320 off_t in_ofs,
321 size_t size,
322 bufferlist& output,
323 off_t stream_offset)
324 {
325 bool result = false;
326 size_t aligned_size = size / AES_256_IVSIZE * AES_256_IVSIZE;
327 size_t unaligned_rest_size = size - aligned_size;
328 output.clear();
329 buffer::ptr buf(aligned_size + AES_256_IVSIZE);
330 unsigned char* buf_raw = reinterpret_cast<unsigned char*>(buf.c_str());
331 const unsigned char* input_raw = reinterpret_cast<const unsigned char*>(input.c_str());
332
333 /* encrypt main bulk of data */
334 result = cbc_transform(buf_raw,
335 input_raw + in_ofs,
336 aligned_size,
337 stream_offset, key, true);
338 if (result && (unaligned_rest_size > 0)) {
339 /* remainder to encrypt */
340 if (aligned_size % CHUNK_SIZE > 0) {
341 /* use last chunk for unaligned part */
342 unsigned char iv[AES_256_IVSIZE] = {0};
343 result = cbc_transform(buf_raw + aligned_size,
344 buf_raw + aligned_size - AES_256_IVSIZE,
345 AES_256_IVSIZE,
346 iv, key, true);
347 } else {
348 /* 0 full blocks in current chunk, use IV as base for unaligned part */
349 unsigned char iv[AES_256_IVSIZE] = {0};
350 unsigned char data[AES_256_IVSIZE];
351 prepare_iv(data, stream_offset + aligned_size);
352 result = cbc_transform(buf_raw + aligned_size,
353 data,
354 AES_256_IVSIZE,
355 iv, key, true);
356 }
357 if (result) {
358 for(size_t i = aligned_size; i < size; i++) {
359 *(buf_raw + i) ^= *(input_raw + in_ofs + i);
360 }
361 }
362 }
363 if (result) {
364 ldout(cct, 25) << "Encrypted " << size << " bytes"<< dendl;
365 buf.set_length(size);
366 output.append(buf);
367 } else {
368 ldout(cct, 5) << "Failed to encrypt" << dendl;
369 }
370 return result;
371 }
372
373
374 bool decrypt(bufferlist& input,
375 off_t in_ofs,
376 size_t size,
377 bufferlist& output,
378 off_t stream_offset)
379 {
380 bool result = false;
381 size_t aligned_size = size / AES_256_IVSIZE * AES_256_IVSIZE;
382 size_t unaligned_rest_size = size - aligned_size;
383 output.clear();
384 buffer::ptr buf(aligned_size + AES_256_IVSIZE);
385 unsigned char* buf_raw = reinterpret_cast<unsigned char*>(buf.c_str());
386 unsigned char* input_raw = reinterpret_cast<unsigned char*>(input.c_str());
387
388 /* decrypt main bulk of data */
389 result = cbc_transform(buf_raw,
390 input_raw + in_ofs,
391 aligned_size,
392 stream_offset, key, false);
393 if (result && unaligned_rest_size > 0) {
394 /* remainder to decrypt */
395 if (aligned_size % CHUNK_SIZE > 0) {
396 /*use last chunk for unaligned part*/
397 unsigned char iv[AES_256_IVSIZE] = {0};
398 result = cbc_transform(buf_raw + aligned_size,
399 input_raw + in_ofs + aligned_size - AES_256_IVSIZE,
400 AES_256_IVSIZE,
401 iv, key, true);
402 } else {
403 /* 0 full blocks in current chunk, use IV as base for unaligned part */
404 unsigned char iv[AES_256_IVSIZE] = {0};
405 unsigned char data[AES_256_IVSIZE];
406 prepare_iv(data, stream_offset + aligned_size);
407 result = cbc_transform(buf_raw + aligned_size,
408 data,
409 AES_256_IVSIZE,
410 iv, key, true);
411 }
412 if (result) {
413 for(size_t i = aligned_size; i < size; i++) {
414 *(buf_raw + i) ^= *(input_raw + in_ofs + i);
415 }
416 }
417 }
418 if (result) {
419 ldout(cct, 25) << "Decrypted " << size << " bytes"<< dendl;
420 buf.set_length(size);
421 output.append(buf);
422 } else {
423 ldout(cct, 5) << "Failed to decrypt" << dendl;
424 }
425 return result;
426 }
427
428
429 void prepare_iv(unsigned char (&iv)[AES_256_IVSIZE], off_t offset) {
430 off_t index = offset / AES_256_IVSIZE;
431 off_t i = AES_256_IVSIZE - 1;
432 unsigned int val;
433 unsigned int carry = 0;
434 while (i>=0) {
435 val = (index & 0xff) + IV[i] + carry;
436 iv[i] = val;
437 carry = val >> 8;
438 index = index >> 8;
439 i--;
440 }
441 }
442 };
443
444
445 std::unique_ptr<BlockCrypt> AES_256_CBC_create(CephContext* cct, const uint8_t* key, size_t len)
446 {
447 auto cbc = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(cct));
448 cbc->set_key(key, AES_256_KEYSIZE);
449 return std::move(cbc);
450 }
451
452
453 const uint8_t AES_256_CBC::IV[AES_256_CBC::AES_256_IVSIZE] =
454 { 'a', 'e', 's', '2', '5', '6', 'i', 'v', '_', 'c', 't', 'r', '1', '3', '3', '7' };
455
456
457 #ifdef USE_NSS
458
459 bool AES_256_ECB_encrypt(CephContext* cct,
460 const uint8_t* key,
461 size_t key_size,
462 const uint8_t* data_in,
463 uint8_t* data_out,
464 size_t data_size) {
465 bool result = false;
466 PK11SlotInfo *slot;
467 SECItem keyItem;
468 PK11SymKey *symkey;
469 SECItem *param;
470 SECStatus ret;
471 PK11Context *ectx;
472 int written;
473 unsigned int written2;
474 if (key_size == AES_256_KEYSIZE) {
475 slot = PK11_GetBestSlot(CKM_AES_ECB, NULL);
476 if (slot) {
477 keyItem.type = siBuffer;
478 keyItem.data = const_cast<uint8_t*>(key);
479 keyItem.len = AES_256_KEYSIZE;
480
481 param = PK11_ParamFromIV(CKM_AES_ECB, NULL);
482 if (param) {
483 symkey = PK11_ImportSymKey(slot, CKM_AES_ECB, PK11_OriginUnwrap, CKA_UNWRAP, &keyItem, NULL);
484 if (symkey) {
485 ectx = PK11_CreateContextBySymKey(CKM_AES_ECB, CKA_ENCRYPT, symkey, param);
486 if (ectx) {
487 ret = PK11_CipherOp(ectx,
488 data_out, &written, data_size,
489 data_in, data_size);
490 if (ret == SECSuccess) {
491 ret = PK11_DigestFinal(ectx,
492 data_out + written, &written2,
493 data_size - written);
494 if (ret == SECSuccess) {
495 result = true;
496 }
497 }
498 PK11_DestroyContext(ectx, PR_TRUE);
499 }
500 PK11_FreeSymKey(symkey);
501 }
502 SECITEM_FreeItem(param, PR_TRUE);
503 }
504 PK11_FreeSlot(slot);
505 }
506 if (result == false) {
507 ldout(cct, 5) << "Failed to perform AES-ECB encryption: " << PR_GetError() << dendl;
508 }
509 } else {
510 ldout(cct, 5) << "Key size must be 256 bits long" << dendl;
511 }
512 return result;
513 }
514
515 #else
516 # error "No supported crypto implementation found."
517 #endif
518
519
520 RGWGetObj_BlockDecrypt::RGWGetObj_BlockDecrypt(CephContext* cct,
521 RGWGetObj_Filter* next,
522 std::unique_ptr<BlockCrypt> crypt):
523 RGWGetObj_Filter(next),
524 cct(cct),
525 crypt(std::move(crypt)),
526 enc_begin_skip(0),
527 ofs(0),
528 end(0),
529 cache()
530 {
531 block_size = this->crypt->get_block_size();
532 }
533
534 RGWGetObj_BlockDecrypt::~RGWGetObj_BlockDecrypt() {
535 }
536
537 int RGWGetObj_BlockDecrypt::read_manifest(bufferlist& manifest_bl) {
538 parts_len.clear();
539 RGWObjManifest manifest;
540 if (manifest_bl.length()) {
541 auto miter = manifest_bl.cbegin();
542 try {
543 decode(manifest, miter);
544 } catch (buffer::error& err) {
545 ldout(cct, 0) << "ERROR: couldn't decode manifest" << dendl;
546 return -EIO;
547 }
548 RGWObjManifest::obj_iterator mi;
549 for (mi = manifest.obj_begin(); mi != manifest.obj_end(); ++mi) {
550 if (mi.get_cur_stripe() == 0) {
551 parts_len.push_back(0);
552 }
553 parts_len.back() += mi.get_stripe_size();
554 }
555 if (cct->_conf->subsys.should_gather<ceph_subsys_rgw, 20>()) {
556 for (size_t i = 0; i<parts_len.size(); i++) {
557 ldout(cct, 20) << "Manifest part " << i << ", size=" << parts_len[i] << dendl;
558 }
559 }
560 }
561 return 0;
562 }
563
564 int RGWGetObj_BlockDecrypt::fixup_range(off_t& bl_ofs, off_t& bl_end) {
565 off_t inp_ofs = bl_ofs;
566 off_t inp_end = bl_end;
567 if (parts_len.size() > 0) {
568 off_t in_ofs = bl_ofs;
569 off_t in_end = bl_end;
570
571 size_t i = 0;
572 while (i<parts_len.size() && (in_ofs >= (off_t)parts_len[i])) {
573 in_ofs -= parts_len[i];
574 i++;
575 }
576 //in_ofs is inside block i
577 size_t j = 0;
578 while (j<(parts_len.size() - 1) && (in_end >= (off_t)parts_len[j])) {
579 in_end -= parts_len[j];
580 j++;
581 }
582 //in_end is inside part j, OR j is the last part
583
584 size_t rounded_end = ( in_end & ~(block_size - 1) ) + (block_size - 1);
585 if (rounded_end > parts_len[j]) {
586 rounded_end = parts_len[j] - 1;
587 }
588
589 enc_begin_skip = in_ofs & (block_size - 1);
590 ofs = bl_ofs - enc_begin_skip;
591 end = bl_end;
592 bl_end += rounded_end - in_end;
593 bl_ofs = std::min(bl_ofs - enc_begin_skip, bl_end);
594 }
595 else
596 {
597 enc_begin_skip = bl_ofs & (block_size - 1);
598 ofs = bl_ofs & ~(block_size - 1);
599 end = bl_end;
600 bl_ofs = bl_ofs & ~(block_size - 1);
601 bl_end = ( bl_end & ~(block_size - 1) ) + (block_size - 1);
602 }
603 ldout(cct, 20) << "fixup_range [" << inp_ofs << "," << inp_end
604 << "] => [" << bl_ofs << "," << bl_end << "]" << dendl;
605 return 0;
606 }
607
608 int RGWGetObj_BlockDecrypt::process(bufferlist& in, size_t part_ofs, size_t size)
609 {
610 bufferlist data;
611 if (!crypt->decrypt(in, 0, size, data, part_ofs)) {
612 return -ERR_INTERNAL_ERROR;
613 }
614 off_t send_size = size - enc_begin_skip;
615 if (ofs + enc_begin_skip + send_size > end + 1) {
616 send_size = end + 1 - ofs - enc_begin_skip;
617 }
618 int res = next->handle_data(data, enc_begin_skip, send_size);
619 enc_begin_skip = 0;
620 ofs += size;
621 in.splice(0, size);
622 return res;
623 }
624
625 int RGWGetObj_BlockDecrypt::handle_data(bufferlist& bl, off_t bl_ofs, off_t bl_len) {
626 ldout(cct, 25) << "Decrypt " << bl_len << " bytes" << dendl;
627 bl.copy(bl_ofs, bl_len, cache);
628
629 int res = 0;
630 size_t part_ofs = ofs;
631 for (size_t part : parts_len) {
632 if (part_ofs >= part) {
633 part_ofs -= part;
634 } else if (part_ofs + cache.length() >= part) {
635 // flush data up to part boundaries, aligned or not
636 res = process(cache, part_ofs, part - part_ofs);
637 if (res < 0) {
638 return res;
639 }
640 part_ofs = 0;
641 } else {
642 break;
643 }
644 }
645 // write up to block boundaries, aligned only
646 off_t aligned_size = cache.length() & ~(block_size - 1);
647 if (aligned_size > 0) {
648 res = process(cache, part_ofs, aligned_size);
649 }
650 return res;
651 }
652
653 /**
654 * flush remainder of data to output
655 */
656 int RGWGetObj_BlockDecrypt::flush() {
657 ldout(cct, 25) << "Decrypt flushing " << cache.length() << " bytes" << dendl;
658 int res = 0;
659 size_t part_ofs = ofs;
660 for (size_t part : parts_len) {
661 if (part_ofs >= part) {
662 part_ofs -= part;
663 } else if (part_ofs + cache.length() >= part) {
664 // flush data up to part boundaries, aligned or not
665 res = process(cache, part_ofs, part - part_ofs);
666 if (res < 0) {
667 return res;
668 }
669 part_ofs = 0;
670 } else {
671 break;
672 }
673 }
674 // flush up to block boundaries, aligned or not
675 if (cache.length() > 0) {
676 res = process(cache, part_ofs, cache.length());
677 }
678 return res;
679 }
680
681 RGWPutObj_BlockEncrypt::RGWPutObj_BlockEncrypt(CephContext* cct,
682 rgw::putobj::DataProcessor *next,
683 std::unique_ptr<BlockCrypt> crypt)
684 : Pipe(next),
685 cct(cct),
686 crypt(std::move(crypt)),
687 block_size(this->crypt->get_block_size())
688 {
689 }
690
691 int RGWPutObj_BlockEncrypt::process(bufferlist&& data, uint64_t logical_offset)
692 {
693 ldout(cct, 25) << "Encrypt " << data.length() << " bytes" << dendl;
694
695 // adjust logical offset to beginning of cached data
696 ceph_assert(logical_offset >= cache.length());
697 logical_offset -= cache.length();
698
699 const bool flush = (data.length() == 0);
700 cache.claim_append(data);
701
702 uint64_t proc_size = cache.length() & ~(block_size - 1);
703 if (flush) {
704 proc_size = cache.length();
705 }
706 if (proc_size > 0) {
707 bufferlist in, out;
708 cache.splice(0, proc_size, &in);
709 if (!crypt->encrypt(in, 0, proc_size, out, logical_offset)) {
710 return -ERR_INTERNAL_ERROR;
711 }
712 int r = Pipe::process(std::move(out), logical_offset);
713 logical_offset += proc_size;
714 if (r < 0)
715 return r;
716 }
717
718 if (flush) {
719 /*replicate 0-sized handle_data*/
720 return Pipe::process({}, logical_offset);
721 }
722 return 0;
723 }
724
725
726 std::string create_random_key_selector(CephContext * const cct) {
727 char random[AES_256_KEYSIZE];
728 cct->random()->get_bytes(&random[0], sizeof(random));
729 return std::string(random, sizeof(random));
730 }
731
732 static int get_barbican_url(CephContext * const cct,
733 std::string& url)
734 {
735 url = cct->_conf->rgw_barbican_url;
736 if (url.empty()) {
737 ldout(cct, 0) << "ERROR: conf rgw_barbican_url is not set" << dendl;
738 return -EINVAL;
739 }
740
741 if (url.back() != '/') {
742 url.append("/");
743 }
744
745 return 0;
746 }
747
748 static int request_key_from_barbican(CephContext *cct,
749 boost::string_view key_id,
750 boost::string_view key_selector,
751 const std::string& barbican_token,
752 std::string& actual_key) {
753 std::string secret_url;
754 int res;
755 res = get_barbican_url(cct, secret_url);
756 if (res < 0) {
757 return res;
758 }
759 secret_url += "v1/secrets/" + std::string(key_id);
760
761 bufferlist secret_bl;
762 RGWHTTPTransceiver secret_req(cct, "GET", secret_url, &secret_bl);
763 secret_req.append_header("Accept", "application/octet-stream");
764 secret_req.append_header("X-Auth-Token", barbican_token);
765
766 res = secret_req.process();
767 if (res < 0) {
768 return res;
769 }
770 if (secret_req.get_http_status() ==
771 RGWHTTPTransceiver::HTTP_STATUS_UNAUTHORIZED) {
772 return -EACCES;
773 }
774
775 if (secret_req.get_http_status() >=200 &&
776 secret_req.get_http_status() < 300 &&
777 secret_bl.length() == AES_256_KEYSIZE) {
778 actual_key.assign(secret_bl.c_str(), secret_bl.length());
779 memset(secret_bl.c_str(), 0, secret_bl.length());
780 } else {
781 res = -EACCES;
782 }
783 return res;
784 }
785
786 static map<string,string> get_str_map(const string &str) {
787 map<string,string> m;
788 get_str_map(str, &m, ";, \t");
789 return m;
790 }
791
792 static int get_actual_key_from_kms(CephContext *cct,
793 boost::string_view key_id,
794 boost::string_view key_selector,
795 std::string& actual_key)
796 {
797 int res = 0;
798 ldout(cct, 20) << "Getting KMS encryption key for key=" << key_id << dendl;
799 static map<string,string> str_map = get_str_map(
800 cct->_conf->rgw_crypt_s3_kms_encryption_keys);
801
802 map<string, string>::iterator it = str_map.find(std::string(key_id));
803 if (it != str_map.end() ) {
804 std::string master_key;
805 try {
806 master_key = from_base64((*it).second);
807 } catch (...) {
808 ldout(cct, 5) << "ERROR: get_actual_key_from_kms invalid encryption key id "
809 << "which contains character that is not base64 encoded."
810 << dendl;
811 return -EINVAL;
812 }
813
814 if (master_key.length() == AES_256_KEYSIZE) {
815 uint8_t _actual_key[AES_256_KEYSIZE];
816 if (AES_256_ECB_encrypt(cct,
817 reinterpret_cast<const uint8_t*>(master_key.c_str()), AES_256_KEYSIZE,
818 reinterpret_cast<const uint8_t*>(key_selector.data()),
819 _actual_key, AES_256_KEYSIZE)) {
820 actual_key = std::string((char*)&_actual_key[0], AES_256_KEYSIZE);
821 } else {
822 res = -EIO;
823 }
824 memset(_actual_key, 0, sizeof(_actual_key));
825 } else {
826 ldout(cct, 20) << "Wrong size for key=" << key_id << dendl;
827 res = -EIO;
828 }
829 } else {
830 std::string token;
831 if (rgw::keystone::Service::get_keystone_barbican_token(cct, token) < 0) {
832 ldout(cct, 5) << "Failed to retrieve token for barbican" << dendl;
833 res = -EINVAL;
834 return res;
835 }
836
837 res = request_key_from_barbican(cct, key_id, key_selector, token, actual_key);
838 if (res != 0) {
839 ldout(cct, 5) << "Failed to retrieve secret from barbican:" << key_id << dendl;
840 }
841 }
842 return res;
843 }
844
845 static inline void set_attr(map<string, bufferlist>& attrs,
846 const char* key,
847 boost::string_view value)
848 {
849 bufferlist bl;
850 bl.append(value.data(), value.size());
851 attrs[key] = std::move(bl);
852 }
853
854 static inline std::string get_str_attribute(map<string, bufferlist>& attrs,
855 const char *name)
856 {
857 auto iter = attrs.find(name);
858 if (iter == attrs.end()) {
859 return {};
860 }
861 return iter->second.to_str();
862 }
863
864 typedef enum {
865 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM=0,
866 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY,
867 X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5,
868 X_AMZ_SERVER_SIDE_ENCRYPTION,
869 X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID,
870 X_AMZ_SERVER_SIDE_ENCRYPTION_LAST
871 } crypt_option_e;
872
873 typedef struct {
874 const char* http_header_name;
875 const std::string post_part_name;
876 } crypt_option_names;
877
878 static const crypt_option_names crypt_options[] = {
879 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", "x-amz-server-side-encryption-customer-algorithm"},
880 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", "x-amz-server-side-encryption-customer-key"},
881 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "x-amz-server-side-encryption-customer-key-md5"},
882 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION", "x-amz-server-side-encryption"},
883 {"HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID", "x-amz-server-side-encryption-aws-kms-key-id"},
884 };
885
886 static boost::string_view get_crypt_attribute(
887 const RGWEnv* env,
888 std::map<std::string,
889 RGWPostObj_ObjStore::post_form_part,
890 const ltstr_nocase>* parts,
891 crypt_option_e option)
892 {
893 static_assert(
894 X_AMZ_SERVER_SIDE_ENCRYPTION_LAST == sizeof(crypt_options)/sizeof(*crypt_options),
895 "Missing items in crypt_options");
896 if (parts != nullptr) {
897 auto iter
898 = parts->find(crypt_options[option].post_part_name);
899 if (iter == parts->end())
900 return boost::string_view();
901 bufferlist& data = iter->second.data;
902 boost::string_view str = boost::string_view(data.c_str(), data.length());
903 return rgw_trim_whitespace(str);
904 } else {
905 const char* hdr = env->get(crypt_options[option].http_header_name, nullptr);
906 if (hdr != nullptr) {
907 return boost::string_view(hdr);
908 } else {
909 return boost::string_view();
910 }
911 }
912 }
913
914
915 int rgw_s3_prepare_encrypt(struct req_state* s,
916 std::map<std::string, ceph::bufferlist>& attrs,
917 std::map<std::string,
918 RGWPostObj_ObjStore::post_form_part,
919 const ltstr_nocase>* parts,
920 std::unique_ptr<BlockCrypt>* block_crypt,
921 std::map<std::string, std::string>& crypt_http_responses)
922 {
923 int res = 0;
924 crypt_http_responses.clear();
925 {
926 boost::string_view req_sse_ca =
927 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM);
928 if (! req_sse_ca.empty()) {
929 if (req_sse_ca != "AES256") {
930 ldout(s->cct, 5) << "ERROR: Invalid value for header "
931 << "x-amz-server-side-encryption-customer-algorithm"
932 << dendl;
933 s->err.message = "The requested encryption algorithm is not valid, must be AES256.";
934 return -ERR_INVALID_ENCRYPTION_ALGORITHM;
935 }
936 if (s->cct->_conf->rgw_crypt_require_ssl &&
937 !rgw_transport_is_secure(s->cct, *s->info.env)) {
938 ldout(s->cct, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl;
939 return -ERR_INVALID_REQUEST;
940 }
941
942 std::string key_bin;
943 try {
944 key_bin = from_base64(
945 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY) );
946 } catch (...) {
947 ldout(s->cct, 5) << "ERROR: rgw_s3_prepare_encrypt invalid encryption "
948 << "key which contains character that is not base64 encoded."
949 << dendl;
950 s->err.message = "Requests specifying Server Side Encryption with Customer "
951 "provided keys must provide an appropriate secret key.";
952 return -EINVAL;
953 }
954
955 if (key_bin.size() != AES_256_CBC::AES_256_KEYSIZE) {
956 ldout(s->cct, 5) << "ERROR: invalid encryption key size" << dendl;
957 s->err.message = "Requests specifying Server Side Encryption with Customer "
958 "provided keys must provide an appropriate secret key.";
959 return -EINVAL;
960 }
961
962 boost::string_view keymd5 =
963 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5);
964
965 std::string keymd5_bin;
966 try {
967 keymd5_bin = from_base64(keymd5);
968 } catch (...) {
969 ldout(s->cct, 5) << "ERROR: rgw_s3_prepare_encrypt invalid encryption key "
970 << "md5 which contains character that is not base64 encoded."
971 << dendl;
972 s->err.message = "Requests specifying Server Side Encryption with Customer "
973 "provided keys must provide an appropriate secret key md5.";
974 return -EINVAL;
975 }
976
977 if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
978 ldout(s->cct, 5) << "ERROR: Invalid key md5 size" << dendl;
979 s->err.message = "Requests specifying Server Side Encryption with Customer "
980 "provided keys must provide an appropriate secret key md5.";
981 return -EINVAL;
982 }
983
984 MD5 key_hash;
985 unsigned char key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE];
986 key_hash.Update(reinterpret_cast<const unsigned char*>(key_bin.c_str()), key_bin.size());
987 key_hash.Final(key_hash_res);
988
989 if (memcmp(key_hash_res, keymd5_bin.c_str(), CEPH_CRYPTO_MD5_DIGESTSIZE) != 0) {
990 ldout(s->cct, 5) << "ERROR: Invalid key md5 hash" << dendl;
991 s->err.message = "The calculated MD5 hash of the key did not match the hash that was provided.";
992 return -EINVAL;
993 }
994
995 set_attr(attrs, RGW_ATTR_CRYPT_MODE, "SSE-C-AES256");
996 set_attr(attrs, RGW_ATTR_CRYPT_KEYMD5, keymd5_bin);
997
998 if (block_crypt) {
999 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
1000 aes->set_key(reinterpret_cast<const uint8_t*>(key_bin.c_str()), AES_256_KEYSIZE);
1001 *block_crypt = std::move(aes);
1002 }
1003
1004 crypt_http_responses["x-amz-server-side-encryption-customer-algorithm"] = "AES256";
1005 crypt_http_responses["x-amz-server-side-encryption-customer-key-MD5"] = keymd5.to_string();
1006 return 0;
1007 } else {
1008 boost::string_view customer_key =
1009 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY);
1010 if (!customer_key.empty()) {
1011 ldout(s->cct, 5) << "ERROR: SSE-C encryption request is missing the header "
1012 << "x-amz-server-side-encryption-customer-algorithm"
1013 << dendl;
1014 s->err.message = "Requests specifying Server Side Encryption with Customer "
1015 "provided keys must provide a valid encryption algorithm.";
1016 return -EINVAL;
1017 }
1018
1019 boost::string_view customer_key_md5 =
1020 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5);
1021 if (!customer_key_md5.empty()) {
1022 ldout(s->cct, 5) << "ERROR: SSE-C encryption request is missing the header "
1023 << "x-amz-server-side-encryption-customer-algorithm"
1024 << dendl;
1025 s->err.message = "Requests specifying Server Side Encryption with Customer "
1026 "provided keys must provide a valid encryption algorithm.";
1027 return -EINVAL;
1028 }
1029 }
1030
1031 /* AMAZON server side encryption with KMS (key management service) */
1032 boost::string_view req_sse =
1033 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION);
1034 if (! req_sse.empty()) {
1035 if (req_sse != "aws:kms") {
1036 ldout(s->cct, 5) << "ERROR: Invalid value for header x-amz-server-side-encryption"
1037 << dendl;
1038 s->err.message = "Server Side Encryption with KMS managed key requires "
1039 "HTTP header x-amz-server-side-encryption : aws:kms";
1040 return -EINVAL;
1041 }
1042 if (s->cct->_conf->rgw_crypt_require_ssl &&
1043 !rgw_transport_is_secure(s->cct, *s->info.env)) {
1044 ldout(s->cct, 5) << "ERROR: insecure request, rgw_crypt_require_ssl is set" << dendl;
1045 return -ERR_INVALID_REQUEST;
1046 }
1047 boost::string_view key_id =
1048 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID);
1049 if (key_id.empty()) {
1050 ldout(s->cct, 5) << "ERROR: not provide a valid key id" << dendl;
1051 s->err.message = "Server Side Encryption with KMS managed key requires "
1052 "HTTP header x-amz-server-side-encryption-aws-kms-key-id";
1053 return -ERR_INVALID_ACCESS_KEY;
1054 }
1055 /* try to retrieve actual key */
1056 std::string key_selector = create_random_key_selector(s->cct);
1057 std::string actual_key;
1058 res = get_actual_key_from_kms(s->cct, key_id, key_selector, actual_key);
1059 if (res != 0) {
1060 ldout(s->cct, 5) << "ERROR: failed to retrieve actual key from key_id: " << key_id << dendl;
1061 s->err.message = "Failed to retrieve the actual key, kms-keyid: " + key_id.to_string();
1062 return res;
1063 }
1064 if (actual_key.size() != AES_256_KEYSIZE) {
1065 ldout(s->cct, 5) << "ERROR: key obtained from key_id:" <<
1066 key_id << " is not 256 bit size" << dendl;
1067 s->err.message = "KMS provided an invalid key for the given kms-keyid.";
1068 return -ERR_INVALID_ACCESS_KEY;
1069 }
1070 set_attr(attrs, RGW_ATTR_CRYPT_MODE, "SSE-KMS");
1071 set_attr(attrs, RGW_ATTR_CRYPT_KEYID, key_id);
1072 set_attr(attrs, RGW_ATTR_CRYPT_KEYSEL, key_selector);
1073
1074 if (block_crypt) {
1075 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
1076 aes->set_key(reinterpret_cast<const uint8_t*>(actual_key.c_str()), AES_256_KEYSIZE);
1077 *block_crypt = std::move(aes);
1078 }
1079 actual_key.replace(0, actual_key.length(), actual_key.length(), '\000');
1080
1081 crypt_http_responses["x-amz-server-side-encryption"] = "aws:kms";
1082 crypt_http_responses["x-amz-server-side-encryption-aws-kms-key-id"] = key_id.to_string();
1083 return 0;
1084 } else {
1085 boost::string_view key_id =
1086 get_crypt_attribute(s->info.env, parts, X_AMZ_SERVER_SIDE_ENCRYPTION_AWS_KMS_KEY_ID);
1087 if (!key_id.empty()) {
1088 ldout(s->cct, 5) << "ERROR: SSE-KMS encryption request is missing the header "
1089 << "x-amz-server-side-encryption"
1090 << dendl;
1091 s->err.message = "Server Side Encryption with KMS managed key requires "
1092 "HTTP header x-amz-server-side-encryption : aws:kms";
1093 return -EINVAL;
1094 }
1095 }
1096
1097 /* no other encryption mode, check if default encryption is selected */
1098 if (s->cct->_conf->rgw_crypt_default_encryption_key != "") {
1099 std::string master_encryption_key;
1100 try {
1101 master_encryption_key = from_base64(s->cct->_conf->rgw_crypt_default_encryption_key);
1102 } catch (...) {
1103 ldout(s->cct, 5) << "ERROR: rgw_s3_prepare_encrypt invalid default encryption key "
1104 << "which contains character that is not base64 encoded."
1105 << dendl;
1106 s->err.message = "Requests specifying Server Side Encryption with Customer "
1107 "provided keys must provide an appropriate secret key.";
1108 return -EINVAL;
1109 }
1110
1111 if (master_encryption_key.size() != 256 / 8) {
1112 ldout(s->cct, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl;
1113 /* not an error to return; missing encryption does not inhibit processing */
1114 return 0;
1115 }
1116
1117 set_attr(attrs, RGW_ATTR_CRYPT_MODE, "RGW-AUTO");
1118 std::string key_selector = create_random_key_selector(s->cct);
1119 set_attr(attrs, RGW_ATTR_CRYPT_KEYSEL, key_selector);
1120
1121 uint8_t actual_key[AES_256_KEYSIZE];
1122 if (AES_256_ECB_encrypt(s->cct,
1123 reinterpret_cast<const uint8_t*>(master_encryption_key.c_str()), AES_256_KEYSIZE,
1124 reinterpret_cast<const uint8_t*>(key_selector.c_str()),
1125 actual_key, AES_256_KEYSIZE) != true) {
1126 memset(actual_key, 0, sizeof(actual_key));
1127 return -EIO;
1128 }
1129 if (block_crypt) {
1130 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
1131 aes->set_key(reinterpret_cast<const uint8_t*>(actual_key), AES_256_KEYSIZE);
1132 *block_crypt = std::move(aes);
1133 }
1134 memset(actual_key, 0, sizeof(actual_key));
1135 return 0;
1136 }
1137 }
1138 /*no encryption*/
1139 return 0;
1140 }
1141
1142
1143 int rgw_s3_prepare_decrypt(struct req_state* s,
1144 map<string, bufferlist>& attrs,
1145 std::unique_ptr<BlockCrypt>* block_crypt,
1146 std::map<std::string, std::string>& crypt_http_responses)
1147 {
1148 int res = 0;
1149 std::string stored_mode = get_str_attribute(attrs, RGW_ATTR_CRYPT_MODE);
1150 ldout(s->cct, 15) << "Encryption mode: " << stored_mode << dendl;
1151
1152 const char *req_sse = s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION", NULL);
1153 if (nullptr != req_sse && (s->op == OP_GET || s->op == OP_HEAD)) {
1154 return -ERR_INVALID_REQUEST;
1155 }
1156
1157 if (stored_mode == "SSE-C-AES256") {
1158 if (s->cct->_conf->rgw_crypt_require_ssl &&
1159 !rgw_transport_is_secure(s->cct, *s->info.env)) {
1160 ldout(s->cct, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl;
1161 return -ERR_INVALID_REQUEST;
1162 }
1163 const char *req_cust_alg =
1164 s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM", NULL);
1165
1166 if (nullptr == req_cust_alg) {
1167 ldout(s->cct, 5) << "ERROR: Request for SSE-C encrypted object missing "
1168 << "x-amz-server-side-encryption-customer-algorithm"
1169 << dendl;
1170 s->err.message = "Requests specifying Server Side Encryption with Customer "
1171 "provided keys must provide a valid encryption algorithm.";
1172 return -EINVAL;
1173 } else if (strcmp(req_cust_alg, "AES256") != 0) {
1174 ldout(s->cct, 5) << "ERROR: The requested encryption algorithm is not valid, must be AES256." << dendl;
1175 s->err.message = "The requested encryption algorithm is not valid, must be AES256.";
1176 return -ERR_INVALID_ENCRYPTION_ALGORITHM;
1177 }
1178
1179 std::string key_bin;
1180 try {
1181 key_bin = from_base64(s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY", ""));
1182 } catch (...) {
1183 ldout(s->cct, 5) << "ERROR: rgw_s3_prepare_decrypt invalid encryption key "
1184 << "which contains character that is not base64 encoded."
1185 << dendl;
1186 s->err.message = "Requests specifying Server Side Encryption with Customer "
1187 "provided keys must provide an appropriate secret key.";
1188 return -EINVAL;
1189 }
1190
1191 if (key_bin.size() != AES_256_CBC::AES_256_KEYSIZE) {
1192 ldout(s->cct, 5) << "ERROR: Invalid encryption key size" << dendl;
1193 s->err.message = "Requests specifying Server Side Encryption with Customer "
1194 "provided keys must provide an appropriate secret key.";
1195 return -EINVAL;
1196 }
1197
1198 std::string keymd5 =
1199 s->info.env->get("HTTP_X_AMZ_SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5", "");
1200 std::string keymd5_bin;
1201 try {
1202 keymd5_bin = from_base64(keymd5);
1203 } catch (...) {
1204 ldout(s->cct, 5) << "ERROR: rgw_s3_prepare_decrypt invalid encryption key md5 "
1205 << "which contains character that is not base64 encoded."
1206 << dendl;
1207 s->err.message = "Requests specifying Server Side Encryption with Customer "
1208 "provided keys must provide an appropriate secret key md5.";
1209 return -EINVAL;
1210 }
1211
1212
1213 if (keymd5_bin.size() != CEPH_CRYPTO_MD5_DIGESTSIZE) {
1214 ldout(s->cct, 5) << "ERROR: Invalid key md5 size " << dendl;
1215 s->err.message = "Requests specifying Server Side Encryption with Customer "
1216 "provided keys must provide an appropriate secret key md5.";
1217 return -EINVAL;
1218 }
1219
1220 MD5 key_hash;
1221 uint8_t key_hash_res[CEPH_CRYPTO_MD5_DIGESTSIZE];
1222 key_hash.Update(reinterpret_cast<const unsigned char*>(key_bin.c_str()), key_bin.size());
1223 key_hash.Final(key_hash_res);
1224
1225 if ((memcmp(key_hash_res, keymd5_bin.c_str(), CEPH_CRYPTO_MD5_DIGESTSIZE) != 0) ||
1226 (get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYMD5) != keymd5_bin)) {
1227 s->err.message = "The calculated MD5 hash of the key did not match the hash that was provided.";
1228 return -EINVAL;
1229 }
1230 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
1231 aes->set_key(reinterpret_cast<const uint8_t*>(key_bin.c_str()), AES_256_CBC::AES_256_KEYSIZE);
1232 if (block_crypt) *block_crypt = std::move(aes);
1233
1234 crypt_http_responses["x-amz-server-side-encryption-customer-algorithm"] = "AES256";
1235 crypt_http_responses["x-amz-server-side-encryption-customer-key-MD5"] = keymd5;
1236 return 0;
1237 }
1238
1239 if (stored_mode == "SSE-KMS") {
1240 if (s->cct->_conf->rgw_crypt_require_ssl &&
1241 !rgw_transport_is_secure(s->cct, *s->info.env)) {
1242 ldout(s->cct, 5) << "ERROR: Insecure request, rgw_crypt_require_ssl is set" << dendl;
1243 return -ERR_INVALID_REQUEST;
1244 }
1245 /* try to retrieve actual key */
1246 std::string key_id = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYID);
1247 std::string key_selector = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYSEL);
1248 std::string actual_key;
1249 res = get_actual_key_from_kms(s->cct, key_id, key_selector, actual_key);
1250 if (res != 0) {
1251 ldout(s->cct, 10) << "ERROR: failed to retrieve actual key from key_id: " << key_id << dendl;
1252 s->err.message = "Failed to retrieve the actual key, kms-keyid: " + key_id;
1253 return res;
1254 }
1255 if (actual_key.size() != AES_256_KEYSIZE) {
1256 ldout(s->cct, 0) << "ERROR: key obtained from key_id:" <<
1257 key_id << " is not 256 bit size" << dendl;
1258 s->err.message = "KMS provided an invalid key for the given kms-keyid.";
1259 return -ERR_INVALID_ACCESS_KEY;
1260 }
1261
1262 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
1263 aes->set_key(reinterpret_cast<const uint8_t*>(actual_key.c_str()), AES_256_KEYSIZE);
1264 actual_key.replace(0, actual_key.length(), actual_key.length(), '\000');
1265 if (block_crypt) *block_crypt = std::move(aes);
1266
1267 crypt_http_responses["x-amz-server-side-encryption"] = "aws:kms";
1268 crypt_http_responses["x-amz-server-side-encryption-aws-kms-key-id"] = key_id;
1269 return 0;
1270 }
1271
1272 if (stored_mode == "RGW-AUTO") {
1273 std::string master_encryption_key;
1274 try {
1275 master_encryption_key = from_base64(std::string(s->cct->_conf->rgw_crypt_default_encryption_key));
1276 } catch (...) {
1277 ldout(s->cct, 5) << "ERROR: rgw_s3_prepare_decrypt invalid default encryption key "
1278 << "which contains character that is not base64 encoded."
1279 << dendl;
1280 s->err.message = "The default encryption key is not valid base64.";
1281 return -EINVAL;
1282 }
1283
1284 if (master_encryption_key.size() != 256 / 8) {
1285 ldout(s->cct, 0) << "ERROR: failed to decode 'rgw crypt default encryption key' to 256 bit string" << dendl;
1286 return -EIO;
1287 }
1288 std::string attr_key_selector = get_str_attribute(attrs, RGW_ATTR_CRYPT_KEYSEL);
1289 if (attr_key_selector.size() != AES_256_CBC::AES_256_KEYSIZE) {
1290 ldout(s->cct, 0) << "ERROR: missing or invalid " RGW_ATTR_CRYPT_KEYSEL << dendl;
1291 return -EIO;
1292 }
1293 uint8_t actual_key[AES_256_KEYSIZE];
1294 if (AES_256_ECB_encrypt(s->cct,
1295 reinterpret_cast<const uint8_t*>(master_encryption_key.c_str()),
1296 AES_256_KEYSIZE,
1297 reinterpret_cast<const uint8_t*>(attr_key_selector.c_str()),
1298 actual_key, AES_256_KEYSIZE) != true) {
1299 memset(actual_key, 0, sizeof(actual_key));
1300 return -EIO;
1301 }
1302 auto aes = std::unique_ptr<AES_256_CBC>(new AES_256_CBC(s->cct));
1303 aes->set_key(actual_key, AES_256_KEYSIZE);
1304 memset(actual_key, 0, sizeof(actual_key));
1305 if (block_crypt) *block_crypt = std::move(aes);
1306 return 0;
1307 }
1308 /*no decryption*/
1309 return 0;
1310 }