C++ Distributed Hash Table
crypto.h
1 /*
2  * Copyright (C) 2014-2017 Savoir-faire Linux Inc.
3  * Author : Adrien BĂ©raud <adrien.beraud@savoirfairelinux.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
19 #pragma once
20 
21 #include "infohash.h"
22 #include "utils.h"
23 #include "rng.h"
24 
25 extern "C" {
26 #include <gnutls/gnutls.h>
27 #include <gnutls/abstract.h>
28 #include <gnutls/x509.h>
29 }
30 
31 #include <vector>
32 #include <memory>
33 
34 #ifdef _WIN32
35 #include <iso646.h>
36 #endif
37 
38 namespace dht {
39 
43 namespace crypto {
44 
45 class OPENDHT_PUBLIC CryptoException : public std::runtime_error {
46  public:
47  CryptoException(const std::string& str) : std::runtime_error(str) {};
48 };
49 
53 class OPENDHT_PUBLIC DecryptError : public CryptoException {
54  public:
55  DecryptError(const std::string& str = "") : CryptoException(str) {};
56 };
57 
58 struct PrivateKey;
59 struct Certificate;
60 class RevocationList;
61 
62 using Identity = std::pair<std::shared_ptr<PrivateKey>, std::shared_ptr<Certificate>>;
63 
67 struct OPENDHT_PUBLIC PublicKey
68 {
69  PublicKey() {}
70 
74  PublicKey(gnutls_pubkey_t k) : pk(k) {}
75  PublicKey(const Blob& pk);
76  PublicKey(PublicKey&& o) noexcept : pk(o.pk) { o.pk = nullptr; };
77 
78  ~PublicKey();
79  explicit operator bool() const { return pk; }
80  bool operator ==(const PublicKey& o) const {
81  return pk == o.pk || getId() == o.getId();
82  }
83  bool operator !=(const PublicKey& o) const {
84  return !(*this == o);
85  }
86 
87  PublicKey& operator=(PublicKey&& o) noexcept;
88 
89  InfoHash getId() const;
90  PkId getLongId() const;
91  bool checkSignature(const Blob& data, const Blob& signature) const;
92  Blob encrypt(const Blob&) const;
93 
94  void pack(Blob& b) const;
95  void unpack(const uint8_t* dat, size_t dat_size);
96 
97  std::string toString() const;
98 
99  template <typename Packer>
100  void msgpack_pack(Packer& p) const
101  {
102  Blob b;
103  pack(b);
104  p.pack_bin(b.size());
105  p.pack_bin_body((const char*)b.data(), b.size());
106  }
107 
108  void msgpack_unpack(msgpack::object o);
109 
110  gnutls_pubkey_t pk {};
111 private:
112  PublicKey(const PublicKey&) = delete;
113  PublicKey& operator=(const PublicKey&) = delete;
114  void encryptBloc(const uint8_t* src, size_t src_size, uint8_t* dst, size_t dst_size) const;
115 };
116 
120 struct OPENDHT_PUBLIC PrivateKey
121 {
122  PrivateKey();
123  //PrivateKey(gnutls_privkey_t k) : key(k) {}
124 
128  PrivateKey(gnutls_x509_privkey_t k);
129 
130  PrivateKey(PrivateKey&& o) noexcept;
131  PrivateKey& operator=(PrivateKey&& o) noexcept;
132 
133  PrivateKey(const Blob& import, const std::string& password = {});
134  ~PrivateKey();
135  explicit operator bool() const { return key; }
136  PublicKey getPublicKey() const;
137  Blob serialize(const std::string& password = {}) const;
138 
143  Blob sign(const Blob&) const;
144 
150  Blob decrypt(const Blob& cypher) const;
151 
158  static PrivateKey generate(unsigned key_length = 4096);
159  static PrivateKey generateEC();
160 
161  gnutls_privkey_t key {};
162  gnutls_x509_privkey_t x509_key {};
163 private:
164  PrivateKey(const PrivateKey&) = delete;
165  PrivateKey& operator=(const PrivateKey&) = delete;
166  Blob decryptBloc(const uint8_t* src, size_t src_size) const;
167 
168  //friend dht::crypto::Identity dht::crypto::generateIdentity(const std::string&, dht::crypto::Identity, unsigned key_length);
169 };
170 
171 
172 class OPENDHT_PUBLIC RevocationList
173 {
174  using clock = std::chrono::system_clock;
175  using time_point = clock::time_point;
176  using duration = clock::duration;
177 public:
178  RevocationList();
179  RevocationList(const Blob& b);
180  RevocationList(RevocationList&& o) : crl(o.crl) { o.crl = nullptr; }
181  ~RevocationList();
182 
183  RevocationList& operator=(RevocationList&& o) { crl = o.crl; o.crl = nullptr; return *this; }
184 
185  void pack(Blob& b) const;
186  void unpack(const uint8_t* dat, size_t dat_size);
187  Blob getPacked() const {
188  Blob b;
189  pack(b);
190  return b;
191  }
192 
193  template <typename Packer>
194  void msgpack_pack(Packer& p) const
195  {
196  Blob b = getPacked();
197  p.pack_bin(b.size());
198  p.pack_bin_body((const char*)b.data(), b.size());
199  }
200 
201  void msgpack_unpack(msgpack::object o);
202 
203  void revoke(const Certificate& crt, time_point t = time_point::min());
204 
205  bool isRevoked(const Certificate& crt) const;
206 
211  void sign(const PrivateKey&, const Certificate&, duration validity_period = {});
212  void sign(const Identity& id) { sign(*id.first, *id.second); }
213 
214  bool isSignedBy(const Certificate& issuer) const;
215 
216  std::string toString() const;
217 
221  Blob getNumber() const;
222 
224  std::string getIssuerName() const;
225 
227  std::string getIssuerUID() const;
228 
229  time_point getUpdateTime() const;
230  time_point getNextUpdateTime() const;
231 
232  gnutls_x509_crl_t get() { return crl; }
233  gnutls_x509_crl_t getCopy() const {
234  if (not crl)
235  return nullptr;
236  auto copy = RevocationList(getPacked());
237  gnutls_x509_crl_t ret = copy.crl;
238  copy.crl = nullptr;
239  return ret;
240  }
241 
242 private:
243  gnutls_x509_crl_t crl {};
244  RevocationList(const RevocationList&) = delete;
245  RevocationList& operator=(const RevocationList&) = delete;
246 };
247 
248 
249 struct OPENDHT_PUBLIC Certificate {
250  Certificate() {}
251 
255  Certificate(gnutls_x509_crt_t crt) : cert(crt) {}
256 
257  Certificate(Certificate&& o) noexcept : cert(o.cert), issuer(std::move(o.issuer)) { o.cert = nullptr; };
258 
263  Certificate(const Blob& crt);
264  Certificate(const std::string& pem) : cert(nullptr) {
265  unpack((const uint8_t*)pem.data(), pem.size());
266  }
267  Certificate(const uint8_t* dat, size_t dat_size) : cert(nullptr) {
268  unpack(dat, dat_size);
269  }
270 
275  template<typename Iterator>
276  Certificate(const Iterator& begin, const Iterator& end) {
277  unpack(begin, end);
278  }
279 
284  template<typename Iterator>
285  Certificate(const std::vector<std::pair<Iterator, Iterator>>& certs) {
286  unpack(certs);
287  }
288 
289  Certificate& operator=(Certificate&& o) noexcept;
290  ~Certificate();
291 
292  void pack(Blob& b) const;
293  void unpack(const uint8_t* dat, size_t dat_size);
294  Blob getPacked() const {
295  Blob b;
296  pack(b);
297  return b;
298  }
299 
308  template<typename Iterator>
309  void unpack(const Iterator& begin, const Iterator& end)
310  {
311  std::shared_ptr<Certificate> tmp_subject {};
312  std::shared_ptr<Certificate> first {};
313  for (Iterator icrt = begin; icrt < end; ++icrt) {
314  auto tmp_crt = std::make_shared<Certificate>(*icrt);
315  if (tmp_subject)
316  tmp_subject->issuer = tmp_crt;
317  tmp_subject = std::move(tmp_crt);
318  if (!first)
319  first = tmp_subject;
320  }
321  *this = first ? std::move(*first) : Certificate();
322  }
323 
335  template<typename Iterator>
336  void unpack(const std::vector<std::pair<Iterator, Iterator>>& certs)
337  {
338  std::shared_ptr<Certificate> tmp_issuer;
339  // reverse iteration
340  for (auto li = certs.rbegin(); li != certs.rend(); ++li) {
341  Certificate tmp_crt;
342  gnutls_x509_crt_init(&tmp_crt.cert);
343  const gnutls_datum_t crt_dt {(uint8_t*)&(*li->first), (unsigned)(li->second-li->first)};
344  int err = gnutls_x509_crt_import(tmp_crt.cert, &crt_dt, GNUTLS_X509_FMT_PEM);
345  if (err != GNUTLS_E_SUCCESS)
346  err = gnutls_x509_crt_import(tmp_crt.cert, &crt_dt, GNUTLS_X509_FMT_DER);
347  if (err != GNUTLS_E_SUCCESS)
348  throw CryptoException(std::string("Could not read certificate - ") + gnutls_strerror(err));
349  tmp_crt.issuer = tmp_issuer;
350  tmp_issuer = std::make_shared<Certificate>(std::move(tmp_crt));
351  }
352  *this = tmp_issuer ? std::move(*tmp_issuer) : Certificate();
353  }
354 
355  template <typename Packer>
356  void msgpack_pack(Packer& p) const
357  {
358  Blob b;
359  pack(b);
360  p.pack_bin(b.size());
361  p.pack_bin_body((const char*)b.data(), b.size());
362  }
363 
364  void msgpack_unpack(msgpack::object o);
365 
366  explicit operator bool() const { return cert; }
367  PublicKey getPublicKey() const;
368 
370  InfoHash getId() const;
371  PkId getLongId() const;
372 
374  std::string getName() const;
375 
377  std::string getUID() const;
378 
380  std::string getIssuerName() const;
381 
383  std::string getIssuerUID() const;
384 
385  enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
386 
388  std::vector<std::pair<NameType, std::string>> getAltNames() const;
389 
390  std::chrono::system_clock::time_point getActivation() const;
391  std::chrono::system_clock::time_point getExpiration() const;
392 
397  bool isCA() const;
398 
403  std::string toString(bool chain = true) const;
404 
405  std::string print() const;
406 
407  void revoke(const PrivateKey&, const Certificate&);
408  std::vector<std::shared_ptr<RevocationList>> getRevocationLists() const;
409  void addRevocationList(RevocationList&&);
410  void addRevocationList(std::shared_ptr<RevocationList>);
411 
412  static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", Identity ca = {}, bool is_ca = false);
413 
414  gnutls_x509_crt_t getCopy() const {
415  if (not cert)
416  return nullptr;
417  auto copy = Certificate(getPacked());
418  gnutls_x509_crt_t ret = copy.cert;
419  copy.cert = nullptr;
420  return ret;
421  }
422 
423  std::vector<gnutls_x509_crt_t>
424  getChain(bool copy = false) const
425  {
426  if (not cert)
427  return {};
428  std::vector<gnutls_x509_crt_t> crts;
429  for (auto c = this; c; c = c->issuer.get())
430  crts.emplace_back(copy ? c->getCopy() : c->cert);
431  return crts;
432  }
433 
434  std::pair<
435  std::vector<gnutls_x509_crt_t>,
436  std::vector<gnutls_x509_crl_t>
437  >
438  getChainWithRevocations(bool copy = false) const
439  {
440  if (not cert)
441  return {};
442  std::vector<gnutls_x509_crt_t> crts;
443  std::vector<gnutls_x509_crl_t> crls;
444  for (auto c = this; c; c = c->issuer.get()) {
445  crts.emplace_back(copy ? c->getCopy() : c->cert);
446  crls.reserve(crls.size() + c->revocation_lists.size());
447  for (const auto& crl : c->revocation_lists)
448  crls.emplace_back(copy ? crl->getCopy() : crl->get());
449  }
450  return {crts, crls};
451  }
452 
453  gnutls_x509_crt_t cert {};
454  std::shared_ptr<Certificate> issuer {};
455 private:
456  Certificate(const Certificate&) = delete;
457  Certificate& operator=(const Certificate&) = delete;
458 
459  struct crlNumberCmp {
460  bool operator() (const std::shared_ptr<RevocationList>& lhs, const std::shared_ptr<RevocationList>& rhs) const {
461  return lhs->getNumber() < rhs->getNumber();
462  }
463  };
464 
465  std::set<std::shared_ptr<RevocationList>, crlNumberCmp> revocation_lists;
466 };
467 
468 struct OPENDHT_PUBLIC TrustList
469 {
470  struct VerifyResult {
471  int ret;
472  unsigned result;
473  bool hasError() const { return ret < 0; }
474  bool isValid() const { return !hasError() and !(result & GNUTLS_CERT_INVALID); }
475  explicit operator bool() const { return isValid(); }
476  std::string toString() const;
477  OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const VerifyResult& h);
478  };
479 
480  TrustList();
481  TrustList(TrustList&& o) : trust(std::move(o.trust)) {
482  o.trust = nullptr;
483  }
484  TrustList& operator=(TrustList&& o);
485  ~TrustList();
486  void add(const Certificate& crt);
487  void add(const RevocationList& crl);
488  void remove(const Certificate& crt, bool parents = true);
489  VerifyResult verify(const Certificate& crt) const;
490 
491 private:
492  TrustList(const TrustList& o) = delete;
493  TrustList& operator=(const TrustList& o) = delete;
494  gnutls_x509_trust_list_t trust;
495 };
496 
497 template <class T>
498 class OPENDHT_PUBLIC secure_vector
499 {
500 public:
501  secure_vector() {}
502  secure_vector(secure_vector<T> const&) = default;
503  secure_vector(secure_vector<T> &&) = default;
504  explicit secure_vector(unsigned size): data_(size) {}
505  explicit secure_vector(unsigned size, T _item): data_(size, _item) {}
506  explicit secure_vector(const std::vector<T>& c): data_(c) {}
507  secure_vector(std::vector<T>&& c): data_(std::move(c)) {}
508  ~secure_vector() { clean(); }
509 
510  static secure_vector<T> getRandom(size_t size) {
511  secure_vector<T> ret(size/sizeof(T));
512  crypto::random_device rdev;
513  std::uniform_int_distribution<uint8_t> rand_byte;
514  std::generate_n((uint8_t*)ret.data_.data(), ret.size()*sizeof(T), std::bind(rand_byte, std::ref(rdev)));
515  return ret;
516  }
517  secure_vector<T>& operator=(const secure_vector<T>& c) {
518  if (&c == this)
519  return *this;
520  clean();
521  data_ = c.data_;
522  return *this;
523  }
524  secure_vector<T>& operator=(secure_vector<T>&& c) {
525  if (&c == this)
526  return *this;
527  clean();
528  data_ = std::move(c.data_);
529  return *this;
530  }
531  secure_vector<T>& operator=(std::vector<T>&& c) {
532  clean();
533  data_ = std::move(c);
534  return *this;
535  }
536  std::vector<T>& writable() { clean(); return data_; }
537  const std::vector<T>& makeInsecure() const { return data_; }
538  const uint8_t* data() const { return data_.data(); }
539 
540  void clean() {
541  clean(data_.begin(), data_.end());
542  }
543 
544  void clear() { clean(); data_.clear(); }
545 
546  size_t size() const { return data_.size(); }
547  bool empty() const { return data_.empty(); }
548 
549  void swap(secure_vector<T>& other) { data_.swap(other.data_); }
550  void resize(size_t s) {
551  if (s == data_.size()) return;
552  if (s < data_.size()) {
553  //shrink
554  clean(data_.begin()+s, data_.end());
555  data_.resize(s);
556  } else {
557  //grow
558  auto data = std::move(data_); // move protected data
559  clear();
560  data_.resize(s);
561  std::copy(data.begin(), data.end(), data_.begin());
562  clean(data.begin(), data.end());
563  }
564  }
565 
566 private:
570  static void clean(const typename std::vector<T>::iterator& i, const typename std::vector<T>::iterator& j) {
571  volatile uint8_t* b = reinterpret_cast<uint8_t*>(&*i);
572  volatile uint8_t* e = reinterpret_cast<uint8_t*>(&*j);
573  std::fill(b, e, 0);
574  }
575 
576  std::vector<T> data_;
577 };
578 
580 
588 OPENDHT_PUBLIC Identity generateIdentity(const std::string& name, Identity ca, unsigned key_length, bool is_ca);
589 OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", Identity ca = {}, unsigned key_length = 4096);
590 
591 OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, Identity ca, bool is_ca);
592 OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", Identity ca = {});
593 
594 
603 OPENDHT_PUBLIC Blob hash(const Blob& data, size_t hash_length = 512/8);
604 
605 OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash, size_t hash_length);
606 
614 OPENDHT_PUBLIC Blob stretchKey(const std::string& password, Blob& salt, size_t key_length = 512/8);
615 
619 OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const Blob& key);
620 OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const std::string& password);
621 
625 OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const Blob& key);
626 OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const std::string& password);
627 
628 }
629 }
Certificate(const Iterator &begin, const Iterator &end)
Definition: crypto.h:276
OPENDHT_PUBLIC Blob hash(const Blob &data, size_t hash_length=512/8)
STL namespace.
OPENDHT_PUBLIC Blob stretchKey(const std::string &password, Blob &salt, size_t key_length=512/8)
Certificate(gnutls_x509_crt_t crt)
Definition: crypto.h:255
void unpack(const std::vector< std::pair< Iterator, Iterator >> &certs)
Definition: crypto.h:336
PublicKey(gnutls_pubkey_t k)
Definition: crypto.h:74
OPENDHT_PUBLIC Blob aesDecrypt(const Blob &data, const Blob &key)
std::vector< uint8_t > Blob
Definition: utils.h:114
OPENDHT_PUBLIC Blob aesEncrypt(const Blob &data, const Blob &key)
OPENDHT_PUBLIC Identity generateIdentity(const std::string &name, Identity ca, unsigned key_length, bool is_ca)
Definition: callbacks.h:34
Certificate(const std::vector< std::pair< Iterator, Iterator >> &certs)
Definition: crypto.h:285
void unpack(const Iterator &begin, const Iterator &end)
Definition: crypto.h:309