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 
92  InfoHash getId() const;
93 
97  PkId getLongId() const;
98 
99  bool checkSignature(const Blob& data, const Blob& signature) const;
100  Blob encrypt(const Blob&) const;
101 
102  void pack(Blob& b) const;
103  void unpack(const uint8_t* dat, size_t dat_size);
104 
105  std::string toString() const;
106 
107  template <typename Packer>
108  void msgpack_pack(Packer& p) const
109  {
110  Blob b;
111  pack(b);
112  p.pack_bin(b.size());
113  p.pack_bin_body((const char*)b.data(), b.size());
114  }
115 
116  void msgpack_unpack(msgpack::object o);
117 
118  gnutls_pubkey_t pk {};
119 private:
120  PublicKey(const PublicKey&) = delete;
121  PublicKey& operator=(const PublicKey&) = delete;
122  void encryptBloc(const uint8_t* src, size_t src_size, uint8_t* dst, size_t dst_size) const;
123 };
124 
128 struct OPENDHT_PUBLIC PrivateKey
129 {
130  PrivateKey();
131  //PrivateKey(gnutls_privkey_t k) : key(k) {}
132 
136  PrivateKey(gnutls_x509_privkey_t k);
137 
138  PrivateKey(PrivateKey&& o) noexcept;
139  PrivateKey& operator=(PrivateKey&& o) noexcept;
140 
141  PrivateKey(const Blob& import, const std::string& password = {});
142  ~PrivateKey();
143  explicit operator bool() const { return key; }
144 
145  PublicKey getPublicKey() const;
146  Blob serialize(const std::string& password = {}) const;
147 
152  Blob sign(const Blob&) const;
153 
159  Blob decrypt(const Blob& cypher) const;
160 
167  static PrivateKey generate(unsigned key_length = 4096);
168  static PrivateKey generateEC();
169 
170  gnutls_privkey_t key {};
171  gnutls_x509_privkey_t x509_key {};
172 private:
173  PrivateKey(const PrivateKey&) = delete;
174  PrivateKey& operator=(const PrivateKey&) = delete;
175  Blob decryptBloc(const uint8_t* src, size_t src_size) const;
176 
177  //friend dht::crypto::Identity dht::crypto::generateIdentity(const std::string&, dht::crypto::Identity, unsigned key_length);
178 };
179 
180 
181 class OPENDHT_PUBLIC RevocationList
182 {
183  using clock = std::chrono::system_clock;
184  using time_point = clock::time_point;
185  using duration = clock::duration;
186 public:
187  RevocationList();
188  RevocationList(const Blob& b);
189  RevocationList(RevocationList&& o) : crl(o.crl) { o.crl = nullptr; }
190  ~RevocationList();
191 
192  RevocationList& operator=(RevocationList&& o) { crl = o.crl; o.crl = nullptr; return *this; }
193 
194  void pack(Blob& b) const;
195  void unpack(const uint8_t* dat, size_t dat_size);
196  Blob getPacked() const {
197  Blob b;
198  pack(b);
199  return b;
200  }
201 
202  template <typename Packer>
203  void msgpack_pack(Packer& p) const
204  {
205  Blob b = getPacked();
206  p.pack_bin(b.size());
207  p.pack_bin_body((const char*)b.data(), b.size());
208  }
209 
210  void msgpack_unpack(msgpack::object o);
211 
212  void revoke(const Certificate& crt, time_point t = time_point::min());
213 
214  bool isRevoked(const Certificate& crt) const;
215 
220  void sign(const PrivateKey&, const Certificate&, duration validity_period = {});
221  void sign(const Identity& id) { sign(*id.first, *id.second); }
222 
223  bool isSignedBy(const Certificate& issuer) const;
224 
225  std::string toString() const;
226 
230  Blob getNumber() const;
231 
233  std::string getIssuerName() const;
234 
236  std::string getIssuerUID() const;
237 
238  time_point getUpdateTime() const;
239  time_point getNextUpdateTime() const;
240 
241  gnutls_x509_crl_t get() { return crl; }
242  gnutls_x509_crl_t getCopy() const {
243  if (not crl)
244  return nullptr;
245  auto copy = RevocationList(getPacked());
246  gnutls_x509_crl_t ret = copy.crl;
247  copy.crl = nullptr;
248  return ret;
249  }
250 
251 private:
252  gnutls_x509_crl_t crl {};
253  RevocationList(const RevocationList&) = delete;
254  RevocationList& operator=(const RevocationList&) = delete;
255 };
256 
257 
258 struct OPENDHT_PUBLIC Certificate {
259  Certificate() {}
260 
264  Certificate(gnutls_x509_crt_t crt) : cert(crt) {}
265 
266  Certificate(Certificate&& o) noexcept : cert(o.cert), issuer(std::move(o.issuer)) { o.cert = nullptr; };
267 
272  Certificate(const Blob& crt);
273  Certificate(const std::string& pem) : cert(nullptr) {
274  unpack((const uint8_t*)pem.data(), pem.size());
275  }
276  Certificate(const uint8_t* dat, size_t dat_size) : cert(nullptr) {
277  unpack(dat, dat_size);
278  }
279 
284  template<typename Iterator>
285  Certificate(const Iterator& begin, const Iterator& end) {
286  unpack(begin, end);
287  }
288 
293  template<typename Iterator>
294  Certificate(const std::vector<std::pair<Iterator, Iterator>>& certs) {
295  unpack(certs);
296  }
297 
298  Certificate& operator=(Certificate&& o) noexcept;
299  ~Certificate();
300 
301  void pack(Blob& b) const;
302  void unpack(const uint8_t* dat, size_t dat_size);
303  Blob getPacked() const {
304  Blob b;
305  pack(b);
306  return b;
307  }
308 
317  template<typename Iterator>
318  void unpack(const Iterator& begin, const Iterator& end)
319  {
320  std::shared_ptr<Certificate> tmp_subject {};
321  std::shared_ptr<Certificate> first {};
322  for (Iterator icrt = begin; icrt < end; ++icrt) {
323  auto tmp_crt = std::make_shared<Certificate>(*icrt);
324  if (tmp_subject)
325  tmp_subject->issuer = tmp_crt;
326  tmp_subject = std::move(tmp_crt);
327  if (!first)
328  first = tmp_subject;
329  }
330  *this = first ? std::move(*first) : Certificate();
331  }
332 
344  template<typename Iterator>
345  void unpack(const std::vector<std::pair<Iterator, Iterator>>& certs)
346  {
347  std::shared_ptr<Certificate> tmp_issuer;
348  // reverse iteration
349  for (auto li = certs.rbegin(); li != certs.rend(); ++li) {
350  Certificate tmp_crt;
351  gnutls_x509_crt_init(&tmp_crt.cert);
352  const gnutls_datum_t crt_dt {(uint8_t*)&(*li->first), (unsigned)(li->second-li->first)};
353  int err = gnutls_x509_crt_import(tmp_crt.cert, &crt_dt, GNUTLS_X509_FMT_PEM);
354  if (err != GNUTLS_E_SUCCESS)
355  err = gnutls_x509_crt_import(tmp_crt.cert, &crt_dt, GNUTLS_X509_FMT_DER);
356  if (err != GNUTLS_E_SUCCESS)
357  throw CryptoException(std::string("Could not read certificate - ") + gnutls_strerror(err));
358  tmp_crt.issuer = tmp_issuer;
359  tmp_issuer = std::make_shared<Certificate>(std::move(tmp_crt));
360  }
361  *this = tmp_issuer ? std::move(*tmp_issuer) : Certificate();
362  }
363 
364  template <typename Packer>
365  void msgpack_pack(Packer& p) const
366  {
367  Blob b;
368  pack(b);
369  p.pack_bin(b.size());
370  p.pack_bin_body((const char*)b.data(), b.size());
371  }
372 
373  void msgpack_unpack(msgpack::object o);
374 
375  explicit operator bool() const { return cert; }
376  PublicKey getPublicKey() const;
377 
379  InfoHash getId() const;
381  PkId getLongId() const;
382 
384  std::string getName() const;
385 
387  std::string getUID() const;
388 
390  std::string getIssuerName() const;
391 
393  std::string getIssuerUID() const;
394 
395  enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
396 
398  std::vector<std::pair<NameType, std::string>> getAltNames() const;
399 
400  std::chrono::system_clock::time_point getActivation() const;
401  std::chrono::system_clock::time_point getExpiration() const;
402 
407  bool isCA() const;
408 
413  std::string toString(bool chain = true) const;
414 
415  std::string print() const;
416 
421  void revoke(const PrivateKey&, const Certificate&);
422 
426  std::vector<std::shared_ptr<RevocationList>> getRevocationLists() const;
427 
431  void addRevocationList(RevocationList&&);
432  void addRevocationList(std::shared_ptr<RevocationList>);
433 
434  static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", Identity ca = {}, bool is_ca = false);
435 
436  gnutls_x509_crt_t getCopy() const {
437  if (not cert)
438  return nullptr;
439  auto copy = Certificate(getPacked());
440  gnutls_x509_crt_t ret = copy.cert;
441  copy.cert = nullptr;
442  return ret;
443  }
444 
445  std::vector<gnutls_x509_crt_t>
446  getChain(bool copy = false) const
447  {
448  if (not cert)
449  return {};
450  std::vector<gnutls_x509_crt_t> crts;
451  for (auto c = this; c; c = c->issuer.get())
452  crts.emplace_back(copy ? c->getCopy() : c->cert);
453  return crts;
454  }
455 
456  std::pair<
457  std::vector<gnutls_x509_crt_t>,
458  std::vector<gnutls_x509_crl_t>
459  >
460  getChainWithRevocations(bool copy = false) const
461  {
462  if (not cert)
463  return {};
464  std::vector<gnutls_x509_crt_t> crts;
465  std::vector<gnutls_x509_crl_t> crls;
466  for (auto c = this; c; c = c->issuer.get()) {
467  crts.emplace_back(copy ? c->getCopy() : c->cert);
468  crls.reserve(crls.size() + c->revocation_lists.size());
469  for (const auto& crl : c->revocation_lists)
470  crls.emplace_back(copy ? crl->getCopy() : crl->get());
471  }
472  return {crts, crls};
473  }
474 
475  gnutls_x509_crt_t cert {};
476  std::shared_ptr<Certificate> issuer {};
477 private:
478  Certificate(const Certificate&) = delete;
479  Certificate& operator=(const Certificate&) = delete;
480 
481  struct crlNumberCmp {
482  bool operator() (const std::shared_ptr<RevocationList>& lhs, const std::shared_ptr<RevocationList>& rhs) const {
483  return lhs->getNumber() < rhs->getNumber();
484  }
485  };
486 
487  std::set<std::shared_ptr<RevocationList>, crlNumberCmp> revocation_lists;
488 };
489 
490 struct OPENDHT_PUBLIC TrustList
491 {
492  struct VerifyResult {
493  int ret;
494  unsigned result;
495  bool hasError() const { return ret < 0; }
496  bool isValid() const { return !hasError() and !(result & GNUTLS_CERT_INVALID); }
497  explicit operator bool() const { return isValid(); }
498  std::string toString() const;
499  OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const VerifyResult& h);
500  };
501 
502  TrustList();
503  TrustList(TrustList&& o) : trust(std::move(o.trust)) {
504  o.trust = nullptr;
505  }
506  TrustList& operator=(TrustList&& o);
507  ~TrustList();
508  void add(const Certificate& crt);
509  void add(const RevocationList& crl);
510  void remove(const Certificate& crt, bool parents = true);
511  VerifyResult verify(const Certificate& crt) const;
512 
513 private:
514  TrustList(const TrustList& o) = delete;
515  TrustList& operator=(const TrustList& o) = delete;
516  gnutls_x509_trust_list_t trust;
517 };
518 
519 template <class T>
520 class OPENDHT_PUBLIC secure_vector
521 {
522 public:
523  secure_vector() {}
524  secure_vector(secure_vector<T> const&) = default;
525  secure_vector(secure_vector<T> &&) = default;
526  explicit secure_vector(unsigned size): data_(size) {}
527  explicit secure_vector(unsigned size, T _item): data_(size, _item) {}
528  explicit secure_vector(const std::vector<T>& c): data_(c) {}
529  secure_vector(std::vector<T>&& c): data_(std::move(c)) {}
530  ~secure_vector() { clean(); }
531 
532  static secure_vector<T> getRandom(size_t size) {
533  secure_vector<T> ret(size);
534  crypto::random_device rdev;
535 #ifdef _WIN32
536  std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint8_t>::max() };
537 #else
538  std::uniform_int_distribution<uint8_t> rand_byte;
539 #endif
540  std::generate_n((uint8_t*)ret.data_.data(), ret.size()*sizeof(T), std::bind(rand_byte, std::ref(rdev)));
541  return ret;
542  }
543  secure_vector<T>& operator=(const secure_vector<T>& c) {
544  if (&c == this)
545  return *this;
546  clean();
547  data_ = c.data_;
548  return *this;
549  }
550  secure_vector<T>& operator=(secure_vector<T>&& c) {
551  if (&c == this)
552  return *this;
553  clean();
554  data_ = std::move(c.data_);
555  return *this;
556  }
557  secure_vector<T>& operator=(std::vector<T>&& c) {
558  clean();
559  data_ = std::move(c);
560  return *this;
561  }
562  std::vector<T>& writable() { clean(); return data_; }
563  const std::vector<T>& makeInsecure() const { return data_; }
564  const uint8_t* data() const { return data_.data(); }
565 
566  void clean() {
567  clean(data_.begin(), data_.end());
568  }
569 
570  void clear() { clean(); data_.clear(); }
571 
572  size_t size() const { return data_.size(); }
573  bool empty() const { return data_.empty(); }
574 
575  void swap(secure_vector<T>& other) { data_.swap(other.data_); }
576  void resize(size_t s) {
577  if (s == data_.size()) return;
578  if (s < data_.size()) {
579  //shrink
580  clean(data_.begin()+s, data_.end());
581  data_.resize(s);
582  } else {
583  //grow
584  auto data = std::move(data_); // move protected data
585  clear();
586  data_.resize(s);
587  std::copy(data.begin(), data.end(), data_.begin());
588  clean(data.begin(), data.end());
589  }
590  }
591 
592 private:
596  static void clean(const typename std::vector<T>::iterator& i, const typename std::vector<T>::iterator& j) {
597  volatile uint8_t* b = reinterpret_cast<uint8_t*>(&*i);
598  volatile uint8_t* e = reinterpret_cast<uint8_t*>(&*j);
599  std::fill(b, e, 0);
600  }
601 
602  std::vector<T> data_;
603 };
604 
606 
614 OPENDHT_PUBLIC Identity generateIdentity(const std::string& name, Identity ca, unsigned key_length, bool is_ca);
615 OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", Identity ca = {}, unsigned key_length = 4096);
616 
617 OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, Identity ca, bool is_ca);
618 OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", Identity ca = {});
619 
620 
629 OPENDHT_PUBLIC Blob hash(const Blob& data, size_t hash_length = 512/8);
630 
631 OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash, size_t hash_length);
632 
640 OPENDHT_PUBLIC Blob stretchKey(const std::string& password, Blob& salt, size_t key_length = 512/8);
641 
645 OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const Blob& key);
646 OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const std::string& password);
647 
651 OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const Blob& key);
652 OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const std::string& password);
653 
654 }
655 }
Certificate(const Iterator &begin, const Iterator &end)
Definition: crypto.h:285
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:264
void unpack(const std::vector< std::pair< Iterator, Iterator >> &certs)
Definition: crypto.h:345
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:294
void unpack(const Iterator &begin, const Iterator &end)
Definition: crypto.h:318