diff --git a/include/opendht/crypto.h b/include/opendht/crypto.h index d4cf548e810b08645fcbe62ae4d44f8c7b7f4e3b..82163aefa76e13422040732f6264a044fb112673 100644 --- a/include/opendht/crypto.h +++ b/include/opendht/crypto.h @@ -53,6 +53,7 @@ class OPENDHT_PUBLIC DecryptError : public CryptoException { struct PrivateKey; struct Certificate; +class RevocationList; using Identity = std::pair<std::shared_ptr<PrivateKey>, std::shared_ptr<Certificate>>; @@ -310,6 +311,11 @@ struct OPENDHT_PUBLIC Certificate { std::string print() const; + void revoke(const PrivateKey&, const Certificate&); + std::vector<std::shared_ptr<RevocationList>> getRevocationLists() const { return revocation_lists; } + void addRevocationList(RevocationList&&); + void addRevocationList(std::shared_ptr<RevocationList>); + static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", Identity ca = {}, bool is_ca = false); gnutls_x509_crt_t cert {}; @@ -317,6 +323,7 @@ struct OPENDHT_PUBLIC Certificate { private: Certificate(const Certificate&) = delete; Certificate& operator=(const Certificate&) = delete; + std::vector<std::shared_ptr<RevocationList>> revocation_lists; }; @@ -340,10 +347,20 @@ public: return b; } - bool isRevoked(const Certificate& crt) const; + template <typename Packer> + void msgpack_pack(Packer& p) const + { + Blob b = getPacked(); + p.pack_bin(b.size()); + p.pack_bin_body((const char*)b.data(), b.size()); + } + + void msgpack_unpack(msgpack::object o); void revoke(const Certificate& crt, time_point t = time_point::min()); + bool isRevoked(const Certificate& crt) const; + /** * Sign this revocation list using provided key and certificate. */ @@ -354,6 +371,11 @@ public: std::string toString() const; + /** + * Read the CRL number extension field. + */ + Blob getNumber() const; + gnutls_x509_crl_t get() { return crl; } private: diff --git a/src/crypto.cpp b/src/crypto.cpp index fc1fedbad0a0c8ed83bed02778464b43922b4b7d..f40337c33fc1c0a96523dfeb224b203b78bdbe1f 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -735,6 +735,30 @@ Certificate::print() const return ret; } +void +Certificate::revoke(const PrivateKey& key, const Certificate& to_revoke) +{ + if (revocation_lists.empty()) + revocation_lists.emplace_back(std::make_shared<RevocationList>()); + auto& list = *revocation_lists.back(); + list.revoke(to_revoke); + list.sign(key, *this); +} + +void +Certificate::addRevocationList(RevocationList&& list) +{ + addRevocationList(std::make_shared<RevocationList>(std::forward<RevocationList>(list))); +} + +void +Certificate::addRevocationList(std::shared_ptr<RevocationList> list) +{ + if (not list->isSignedBy(*this)) + throw CryptoException("CRL is not signed by this certificate"); + revocation_lists.emplace_back(std::move(list)); +} + PrivateKey PrivateKey::generate(unsigned key_length) { @@ -884,6 +908,21 @@ RevocationList::unpack(const uint8_t* dat, size_t dat_size) } } +void +RevocationList::msgpack_unpack(msgpack::object o) +{ + try { + if (o.type == msgpack::type::BIN) + unpack((const uint8_t*)o.via.bin.ptr, o.via.bin.size); + else { + Blob dat = unpackBlob(o); + unpack(dat.data(), dat.size()); + } + } catch (...) { + throw msgpack::type_error(); + } +} + bool RevocationList::isRevoked(const Certificate& crt) const { @@ -965,6 +1004,19 @@ RevocationList::isSignedBy(const Certificate& issuer) const return result == 0; } + +Blob +RevocationList::getNumber() const +{ + Blob number(20); + size_t number_sz {number.size()}; + unsigned critical {0}; + gnutls_x509_crl_get_number(crl, number.data(), &number_sz, &critical); + if (number_sz != number.size()) + number.resize(number_sz); + return number; +} + std::string RevocationList::toString() const {