Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / auth / Crypto.cc
1 // vim: ts=8 sw=2 smarttab
2 /*
3  * Ceph - scalable distributed file system
4  *
5  * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net>
6  *
7  * This is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License version 2.1, as published by the Free Software 
10  * Foundation.  See file COPYING.
11  * 
12  */
13
14 #include <sstream>
15 #include "Crypto.h"
16 #ifdef USE_CRYPTOPP
17 # include <cryptopp/modes.h>
18 # include <cryptopp/aes.h>
19 # include <cryptopp/filters.h>
20 #elif defined(USE_NSS)
21 # include <nspr.h>
22 # include <nss.h>
23 # include <pk11pub.h>
24 #endif
25
26 #include "include/assert.h"
27 #include "common/Clock.h"
28 #include "common/armor.h"
29 #include "common/ceph_crypto.h"
30 #include "common/hex.h"
31 #include "common/safe_io.h"
32 #include "include/ceph_fs.h"
33 #include "include/compat.h"
34 #include "common/Formatter.h"
35 #include "common/debug.h"
36 #include <errno.h>
37
38 int get_random_bytes(char *buf, int len)
39 {
40   int fd = TEMP_FAILURE_RETRY(::open("/dev/urandom", O_RDONLY));
41   if (fd < 0)
42     return -errno;
43   int ret = safe_read_exact(fd, buf, len);
44   VOID_TEMP_FAILURE_RETRY(::close(fd));
45   return ret;
46 }
47
48 static int get_random_bytes(int len, bufferlist& bl)
49 {
50   char buf[len];
51   get_random_bytes(buf, len);
52   bl.append(buf, len);
53   return 0;
54 }
55
56 uint64_t get_random(uint64_t min_val, uint64_t max_val)
57 {
58   uint64_t r;
59   get_random_bytes((char *)&r, sizeof(r));
60   r = min_val + r % (max_val - min_val + 1);
61   return r;
62 }
63
64
65 // ---------------------------------------------------
66
67 class CryptoNoneKeyHandler : public CryptoKeyHandler {
68 public:
69   int encrypt(const bufferlist& in,
70                bufferlist& out, std::string *error) const override {
71     out = in;
72     return 0;
73   }
74   int decrypt(const bufferlist& in,
75               bufferlist& out, std::string *error) const override {
76     out = in;
77     return 0;
78   }
79 };
80
81 class CryptoNone : public CryptoHandler {
82 public:
83   CryptoNone() { }
84   ~CryptoNone() override {}
85   int get_type() const override {
86     return CEPH_CRYPTO_NONE;
87   }
88   int create(bufferptr& secret) override {
89     return 0;
90   }
91   int validate_secret(const bufferptr& secret) override {
92     return 0;
93   }
94   CryptoKeyHandler *get_key_handler(const bufferptr& secret, string& error) override {
95     return new CryptoNoneKeyHandler;
96   }
97 };
98
99
100 // ---------------------------------------------------
101
102
103 class CryptoAES : public CryptoHandler {
104 public:
105   CryptoAES() { }
106   ~CryptoAES() override {}
107   int get_type() const override {
108     return CEPH_CRYPTO_AES;
109   }
110   int create(bufferptr& secret) override;
111   int validate_secret(const bufferptr& secret) override;
112   CryptoKeyHandler *get_key_handler(const bufferptr& secret, string& error) override;
113 };
114
115 #ifdef USE_CRYPTOPP
116 # define AES_KEY_LEN     ((size_t)CryptoPP::AES::DEFAULT_KEYLENGTH)
117 # define AES_BLOCK_LEN   ((size_t)CryptoPP::AES::BLOCKSIZE)
118
119 class CryptoAESKeyHandler : public CryptoKeyHandler {
120 public:
121   CryptoPP::AES::Encryption *enc_key;
122   CryptoPP::AES::Decryption *dec_key;
123
124   CryptoAESKeyHandler()
125     : enc_key(NULL),
126       dec_key(NULL) {}
127   ~CryptoAESKeyHandler() {
128     delete enc_key;
129     delete dec_key;
130   }
131
132   int init(const bufferptr& s, ostringstream& err) {
133     secret = s;
134
135     enc_key = new CryptoPP::AES::Encryption(
136       (byte*)secret.c_str(), CryptoPP::AES::DEFAULT_KEYLENGTH);
137     dec_key = new CryptoPP::AES::Decryption(
138       (byte*)secret.c_str(), CryptoPP::AES::DEFAULT_KEYLENGTH);
139
140     return 0;
141   }
142
143   int encrypt(const bufferlist& in,
144               bufferlist& out, std::string *error) const {
145     string ciphertext;
146     CryptoPP::StringSink *sink = new CryptoPP::StringSink(ciphertext);
147     CryptoPP::CBC_Mode_ExternalCipher::Encryption cbc(
148       *enc_key, (const byte*)CEPH_AES_IV);
149     CryptoPP::StreamTransformationFilter stfEncryptor(cbc, sink);
150
151     for (std::list<bufferptr>::const_iterator it = in.buffers().begin();
152          it != in.buffers().end(); ++it) {
153       const unsigned char *in_buf = (const unsigned char *)it->c_str();
154       stfEncryptor.Put(in_buf, it->length());
155     }
156     try {
157       stfEncryptor.MessageEnd();
158     } catch (CryptoPP::Exception& e) {
159       if (error) {
160         ostringstream oss;
161         oss << "encryptor.MessageEnd::Exception: " << e.GetWhat();
162         *error = oss.str();
163       }
164       return -1;
165     }
166     out.append((const char *)ciphertext.c_str(), ciphertext.length());
167     return 0;
168   }
169
170   int decrypt(const bufferlist& in,
171               bufferlist& out, std::string *error) const {
172     string decryptedtext;
173     CryptoPP::StringSink *sink = new CryptoPP::StringSink(decryptedtext);
174     CryptoPP::CBC_Mode_ExternalCipher::Decryption cbc(
175       *dec_key, (const byte*)CEPH_AES_IV );
176     CryptoPP::StreamTransformationFilter stfDecryptor(cbc, sink);
177     for (std::list<bufferptr>::const_iterator it = in.buffers().begin();
178          it != in.buffers().end(); ++it) {
179       const unsigned char *in_buf = (const unsigned char *)it->c_str();
180       stfDecryptor.Put(in_buf, it->length());
181     }
182
183     try {
184       stfDecryptor.MessageEnd();
185     } catch (CryptoPP::Exception& e) {
186       if (error) {
187         ostringstream oss;
188         oss << "decryptor.MessageEnd::Exception: " << e.GetWhat();
189         *error = oss.str();
190       }
191       return -1;
192     }
193
194     out.append((const char *)decryptedtext.c_str(), decryptedtext.length());
195     return 0;
196   }
197 };
198
199 #elif defined(USE_NSS)
200 // when we say AES, we mean AES-128
201 # define AES_KEY_LEN    16
202 # define AES_BLOCK_LEN   16
203
204 static int nss_aes_operation(CK_ATTRIBUTE_TYPE op,
205                              CK_MECHANISM_TYPE mechanism,
206                              PK11SymKey *key,
207                              SECItem *param,
208                              const bufferlist& in, bufferlist& out,
209                              std::string *error)
210 {
211   // sample source said this has to be at least size of input + 8,
212   // but i see 15 still fail with SEC_ERROR_OUTPUT_LEN
213   bufferptr out_tmp(in.length()+16);
214   bufferlist incopy;
215
216   SECStatus ret;
217   int written;
218   unsigned char *in_buf;
219
220   PK11Context *ectx;
221   ectx = PK11_CreateContextBySymKey(mechanism, op, key, param);
222   assert(ectx);
223
224   incopy = in;  // it's a shallow copy!
225   in_buf = (unsigned char*)incopy.c_str();
226   ret = PK11_CipherOp(ectx,
227                       (unsigned char*)out_tmp.c_str(), &written, out_tmp.length(),
228                       in_buf, in.length());
229   if (ret != SECSuccess) {
230     PK11_DestroyContext(ectx, PR_TRUE);
231     if (error) {
232       ostringstream oss;
233       oss << "NSS AES failed: " << PR_GetError();
234       *error = oss.str();
235     }
236     return -1;
237   }
238
239   unsigned int written2;
240   ret = PK11_DigestFinal(ectx,
241                          (unsigned char*)out_tmp.c_str()+written, &written2,
242                          out_tmp.length()-written);
243   PK11_DestroyContext(ectx, PR_TRUE);
244   if (ret != SECSuccess) {
245     if (error) {
246       ostringstream oss;
247       oss << "NSS AES final round failed: " << PR_GetError();
248       *error = oss.str();
249     }
250     return -1;
251   }
252
253   out_tmp.set_length(written + written2);
254   out.append(out_tmp);
255   return 0;
256 }
257
258 class CryptoAESKeyHandler : public CryptoKeyHandler {
259   CK_MECHANISM_TYPE mechanism;
260   PK11SlotInfo *slot;
261   PK11SymKey *key;
262   SECItem *param;
263
264 public:
265   CryptoAESKeyHandler()
266     : mechanism(CKM_AES_CBC_PAD),
267       slot(NULL),
268       key(NULL),
269       param(NULL) {}
270   ~CryptoAESKeyHandler() override {
271     SECITEM_FreeItem(param, PR_TRUE);
272     if (key)
273       PK11_FreeSymKey(key);
274     if (slot)
275       PK11_FreeSlot(slot);
276   }
277
278   int init(const bufferptr& s, ostringstream& err) {
279     secret = s;
280
281     slot = PK11_GetBestSlot(mechanism, NULL);
282     if (!slot) {
283       err << "cannot find NSS slot to use: " << PR_GetError();
284       return -1;
285     }
286
287     SECItem keyItem;
288     keyItem.type = siBuffer;
289     keyItem.data = (unsigned char*)secret.c_str();
290     keyItem.len = secret.length();
291     key = PK11_ImportSymKey(slot, mechanism, PK11_OriginUnwrap, CKA_ENCRYPT,
292                             &keyItem, NULL);
293     if (!key) {
294       err << "cannot convert AES key for NSS: " << PR_GetError();
295       return -1;
296     }
297
298     SECItem ivItem;
299     ivItem.type = siBuffer;
300     // losing constness due to SECItem.data; IV should never be
301     // modified, regardless
302     ivItem.data = (unsigned char*)CEPH_AES_IV;
303     ivItem.len = sizeof(CEPH_AES_IV);
304
305     param = PK11_ParamFromIV(mechanism, &ivItem);
306     if (!param) {
307       err << "cannot set NSS IV param: " << PR_GetError();
308       return -1;
309     }
310
311     return 0;
312   }
313
314   int encrypt(const bufferlist& in,
315               bufferlist& out, std::string *error) const override {
316     return nss_aes_operation(CKA_ENCRYPT, mechanism, key, param, in, out, error);
317   }
318   int decrypt(const bufferlist& in,
319                bufferlist& out, std::string *error) const override {
320     return nss_aes_operation(CKA_DECRYPT, mechanism, key, param, in, out, error);
321   }
322 };
323
324 #else
325 # error "No supported crypto implementation found."
326 #endif
327
328
329
330 // ------------------------------------------------------------
331
332 int CryptoAES::create(bufferptr& secret)
333 {
334   bufferlist bl;
335   int r = get_random_bytes(AES_KEY_LEN, bl);
336   if (r < 0)
337     return r;
338   secret = buffer::ptr(bl.c_str(), bl.length());
339   return 0;
340 }
341
342 int CryptoAES::validate_secret(const bufferptr& secret)
343 {
344   if (secret.length() < (size_t)AES_KEY_LEN) {
345     return -EINVAL;
346   }
347
348   return 0;
349 }
350
351 CryptoKeyHandler *CryptoAES::get_key_handler(const bufferptr& secret,
352                                              string& error)
353 {
354   CryptoAESKeyHandler *ckh = new CryptoAESKeyHandler;
355   ostringstream oss;
356   if (ckh->init(secret, oss) < 0) {
357     error = oss.str();
358     delete ckh;
359     return NULL;
360   }
361   return ckh;
362 }
363
364
365
366
367 // --
368
369
370 // ---------------------------------------------------
371
372
373 void CryptoKey::encode(bufferlist& bl) const
374 {
375   ::encode(type, bl);
376   ::encode(created, bl);
377   __u16 len = secret.length();
378   ::encode(len, bl);
379   bl.append(secret);
380 }
381
382 void CryptoKey::decode(bufferlist::iterator& bl)
383 {
384   ::decode(type, bl);
385   ::decode(created, bl);
386   __u16 len;
387   ::decode(len, bl);
388   bufferptr tmp;
389   bl.copy_deep(len, tmp);
390   if (_set_secret(type, tmp) < 0)
391     throw buffer::malformed_input("malformed secret");
392 }
393
394 int CryptoKey::set_secret(int type, const bufferptr& s, utime_t c)
395 {
396   int r = _set_secret(type, s);
397   if (r < 0)
398     return r;
399   this->created = c;
400   return 0;
401 }
402
403 int CryptoKey::_set_secret(int t, const bufferptr& s)
404 {
405   if (s.length() == 0) {
406     secret = s;
407     ckh.reset();
408     return 0;
409   }
410
411   CryptoHandler *ch = CryptoHandler::create(t);
412   if (ch) {
413     int ret = ch->validate_secret(s);
414     if (ret < 0) {
415       delete ch;
416       return ret;
417     }
418     string error;
419     ckh.reset(ch->get_key_handler(s, error));
420     delete ch;
421     if (error.length()) {
422       return -EIO;
423     }
424   } else {
425       return -EOPNOTSUPP;
426   }
427   type = t;
428   secret = s;
429   return 0;
430 }
431
432 int CryptoKey::create(CephContext *cct, int t)
433 {
434   CryptoHandler *ch = CryptoHandler::create(t);
435   if (!ch) {
436     if (cct)
437       lderr(cct) << "ERROR: cct->get_crypto_handler(type=" << t << ") returned NULL" << dendl;
438     return -EOPNOTSUPP;
439   }
440   bufferptr s;
441   int r = ch->create(s);
442   delete ch;
443   if (r < 0)
444     return r;
445
446   r = _set_secret(t, s);
447   if (r < 0)
448     return r;
449   created = ceph_clock_now();
450   return r;
451 }
452
453 void CryptoKey::print(std::ostream &out) const
454 {
455   out << encode_base64();
456 }
457
458 void CryptoKey::to_str(std::string& s) const
459 {
460   int len = secret.length() * 4;
461   char buf[len];
462   hex2str(secret.c_str(), secret.length(), buf, len);
463   s = buf;
464 }
465
466 void CryptoKey::encode_formatted(string label, Formatter *f, bufferlist &bl)
467 {
468   f->open_object_section(label.c_str());
469   f->dump_string("key", encode_base64());
470   f->close_section();
471   f->flush(bl);
472 }
473
474 void CryptoKey::encode_plaintext(bufferlist &bl)
475 {
476   bl.append(encode_base64());
477 }
478
479
480 // ------------------
481
482 CryptoHandler *CryptoHandler::create(int type)
483 {
484   switch (type) {
485   case CEPH_CRYPTO_NONE:
486     return new CryptoNone;
487   case CEPH_CRYPTO_AES:
488     return new CryptoAES;
489   default:
490     return NULL;
491   }
492 }