My Project 1.7.4
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
25extern "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
38namespace dht {
39
43namespace crypto {
44
45class OPENDHT_PUBLIC CryptoException : public std::runtime_error {
46 public:
47 CryptoException(const std::string& str) : std::runtime_error(str) {};
48};
49
53class OPENDHT_PUBLIC DecryptError : public CryptoException {
54 public:
55 DecryptError(const std::string& str = "") : CryptoException(str) {};
56};
57
58struct PrivateKey;
59struct Certificate;
60class RevocationList;
61
62using Identity = std::pair<std::shared_ptr<PrivateKey>, std::shared_ptr<Certificate>>;
63
67struct 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 {};
111private:
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
120struct 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 {};
163private:
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
172class OPENDHT_PUBLIC RevocationList
173{
174 using clock = std::chrono::system_clock;
175 using time_point = clock::time_point;
176 using duration = clock::duration;
177public:
179 RevocationList(const Blob& b);
180 RevocationList(RevocationList&& o) : crl(o.crl) { o.crl = nullptr; }
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
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
242private:
243 gnutls_x509_crl_t crl {};
244 RevocationList(const RevocationList&) = delete;
245 RevocationList& operator=(const RevocationList&) = delete;
246};
247
248
249struct 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
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 {};
455private:
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
468struct OPENDHT_PUBLIC TrustList
469{
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
491private:
492 TrustList(const TrustList& o) = delete;
493 TrustList& operator=(const TrustList& o) = delete;
494 gnutls_x509_trust_list_t trust;
495};
496
497template <class T>
498class OPENDHT_PUBLIC secure_vector
499{
500public:
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
566private:
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
588OPENDHT_PUBLIC Identity generateIdentity(const std::string& name, Identity ca, unsigned key_length, bool is_ca);
589OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", Identity ca = {}, unsigned key_length = 4096);
590
591OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, Identity ca, bool is_ca);
592OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", Identity ca = {});
593
594
603OPENDHT_PUBLIC Blob hash(const Blob& data, size_t hash_length = 512/8);
604
605OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash, size_t hash_length);
606
614OPENDHT_PUBLIC Blob stretchKey(const std::string& password, Blob& salt, size_t key_length = 512/8);
615
619OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const Blob& key);
620OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const std::string& password);
621
625OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const Blob& key);
626OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const std::string& password);
627
628}
629}
std::string getIssuerUID() const
void sign(const PrivateKey &, const Certificate &, duration validity_period={})
std::string getIssuerName() const
OPENDHT_PUBLIC Blob stretchKey(const std::string &password, Blob &salt, size_t key_length=512/8)
OPENDHT_PUBLIC Blob hash(const Blob &data, size_t hash_length=512/8)
OPENDHT_PUBLIC Identity generateIdentity(const std::string &name, Identity ca, unsigned key_length, bool is_ca)
OPENDHT_PUBLIC Blob aesDecrypt(const Blob &data, const Blob &key)
OPENDHT_PUBLIC Blob aesEncrypt(const Blob &data, const Blob &key)
Definition: callbacks.h:34
std::vector< uint8_t > Blob
Definition: utils.h:114
std::string getIssuerUID() const
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
Certificate(const Blob &crt)
InfoHash getId() const
Certificate(gnutls_x509_crt_t crt)
Definition: crypto.h:255
Certificate(const Iterator &begin, const Iterator &end)
Definition: crypto.h:276
std::string getIssuerName() const
std::string getUID() const
void unpack(const std::vector< std::pair< Iterator, Iterator > > &certs)
Definition: crypto.h:336
std::string toString(bool chain=true) const
std::string getName() const
std::vector< std::pair< NameType, std::string > > getAltNames() const
Blob decrypt(const Blob &cypher) const
Blob sign(const Blob &) const
static PrivateKey generate(unsigned key_length=4096)
PrivateKey(gnutls_x509_privkey_t k)
PublicKey(gnutls_pubkey_t k)
Definition: crypto.h:74