diff --git a/include/opendht/crypto.h b/include/opendht/crypto.h index 3514ba75badc9d20ea41c6372c94a3117baefa36..9bba9ffd82a7ee8814eab5f425baf790ced85a93 100644 --- a/include/opendht/crypto.h +++ b/include/opendht/crypto.h @@ -308,6 +308,8 @@ struct OPENDHT_PUBLIC Certificate { */ std::string toString(bool chain = true) const; + std::string print() const; + static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", Identity ca = {}, bool is_ca = false); gnutls_x509_crt_t cert {}; @@ -320,14 +322,24 @@ private: class OPENDHT_PUBLIC RevocationList { + using clock = std::chrono::system_clock; + using time_point = clock::time_point; public: RevocationList(); RevocationList(const Blob& b); ~RevocationList(); + void pack(Blob& b) const; + void unpack(const uint8_t* dat, size_t dat_size); + Blob getPacked() const { + Blob b; + pack(b); + return b; + } + bool isRevoked(const Certificate& crt) const; - void revoke(const Certificate& crt, std::chrono::system_clock::time_point t = {}); + void revoke(const Certificate& crt, time_point t = time_point::min()); /** * Sign this revocation list using provided key and certificate. @@ -335,11 +347,9 @@ public: void sign(const PrivateKey&, const Certificate&); void sign(const Identity& id) { sign(*id.first, *id.second); } - bool isIssuedBy(const Certificate& crt); - - bool isValid(const Certificate& issuer); + bool isSignedBy(const Certificate& issuer) const; - std::string toString(); + std::string toString() const; gnutls_x509_crl_t get() { return crl; } diff --git a/src/crypto.cpp b/src/crypto.cpp index f34849a44796a2f3b37ae873293cc9c273ec77ea..4a3c13c6debf99859a9c0e56ba313b6d882322df 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -725,6 +725,16 @@ Certificate::toString(bool chain) const return ss.str(); } +std::string +Certificate::print() const +{ + gnutls_datum_t out; + gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &out); + std::string ret(out.data, out.data+out.size); + gnutls_free(out.data); + return ret; +} + PrivateKey PrivateKey::generate(unsigned key_length) { @@ -834,14 +844,13 @@ RevocationList::RevocationList() RevocationList::RevocationList(const Blob& b) { gnutls_x509_crl_init(&crl); - const gnutls_datum_t gdat {(uint8_t*)b.data(), (unsigned)b.size()}; - if (auto err_pem = gnutls_x509_crl_import(crl, &gdat, GNUTLS_X509_FMT_PEM)) - if (auto err_der = gnutls_x509_crl_import(crl, &gdat, GNUTLS_X509_FMT_DER)) { - gnutls_x509_crl_deinit(crl); - crl = nullptr; - throw CryptoException(std::string("Can't load CRL: PEM: ") + gnutls_strerror(err_pem) - + " DER: " + gnutls_strerror(err_der)); - } + try { + unpack(b.data(), b.size()); + } catch (const std::exception& e) { + gnutls_x509_crl_deinit(crl); + crl = nullptr; + throw e; + } } RevocationList::~RevocationList() @@ -852,6 +861,29 @@ RevocationList::~RevocationList() } } +void +RevocationList::pack(Blob& b) const +{ + gnutls_datum_t gdat {nullptr, 0}; + if (auto err = gnutls_x509_crl_export2(crl, GNUTLS_X509_FMT_PEM, &gdat)) { + throw CryptoException(std::string("Can't export CRL: ") + gnutls_strerror(err)); + } + b.insert(b.end(), gdat.data, gdat.data + gdat.size); +} + +void +RevocationList::unpack(const uint8_t* dat, size_t dat_size) +{ + if (std::numeric_limits<unsigned>::max() < dat_size) + throw CryptoException("Can't load CRL: too large!"); + const gnutls_datum_t gdat {(uint8_t*)dat, (unsigned)dat_size}; + if (auto err_pem = gnutls_x509_crl_import(crl, &gdat, GNUTLS_X509_FMT_PEM)) + if (auto err_der = gnutls_x509_crl_import(crl, &gdat, GNUTLS_X509_FMT_DER)) { + throw CryptoException(std::string("Can't load CRL: PEM: ") + gnutls_strerror(err_pem) + + " DER: " + gnutls_strerror(err_der)); + } +} + bool RevocationList::isRevoked(const Certificate& crt) const { @@ -864,6 +896,8 @@ RevocationList::isRevoked(const Certificate& crt) const void RevocationList::revoke(const Certificate& crt, std::chrono::system_clock::time_point t) { + if (t == time_point::min()) + t = clock::now(); if (auto err = gnutls_x509_crl_set_crt(crl, crt.cert, std::chrono::system_clock::to_time_t(t))) throw CryptoException(std::string("Can't revoke certificate: ") + gnutls_strerror(err)); } @@ -875,7 +909,7 @@ enum class Endian : uint32_t }; template <typename T> -T endian(T w, Endian endian) +T endian(T w, Endian endian = Endian::BIG) { // this gets optimized out into if (endian == host_endian) return w; union { uint64_t quad; uint32_t islittle; } t; @@ -908,9 +942,11 @@ RevocationList::sign(const PrivateKey& key, const Certificate& ca) size_t number_sz {sizeof(number)}; unsigned critical {0}; gnutls_x509_crl_get_number(crl, &number, &number_sz, &critical); - auto s = endian(number, Endian::BIG); - s++; - number = endian(s, Endian::BIG); + if (number == 0) { + number = (uint64_t)1 | ((uint64_t)1 << (7*8)); + number_sz = sizeof(number); + } + number = endian(endian(number) + 1); if (auto err = gnutls_x509_crl_set_number(crl, &number, sizeof(number))) throw CryptoException(std::string("Can't set CRL update time: ") + gnutls_strerror(err)); if (auto err = gnutls_x509_crl_sign2(crl, ca.cert, key.x509_key, GNUTLS_DIG_SHA512, 0)) @@ -918,20 +954,19 @@ RevocationList::sign(const PrivateKey& key, const Certificate& ca) } bool -RevocationList::isIssuedBy(const Certificate& crt) -{ - return gnutls_x509_crl_check_issuer(crl, crt.cert); -} - -bool -RevocationList::isValid(const Certificate& issuer) +RevocationList::isSignedBy(const Certificate& issuer) const { unsigned result {0}; - gnutls_x509_crl_verify(crl, &issuer.cert, 1, 0, &result); + auto err = gnutls_x509_crl_verify(crl, &issuer.cert, 1, 0, &result); + if (err < 0) { + //std::cout << "Can't verify CRL: " << err << " " << result << " " << gnutls_strerror(err) << std::endl; + return false; + } + return result == 0; } std::string -RevocationList::toString() +RevocationList::toString() const { gnutls_datum_t out; gnutls_x509_crl_print(crl, GNUTLS_CRT_PRINT_FULL, &out);