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