diff --git a/include/opendht/crypto.h b/include/opendht/crypto.h index 4340ec83c315411be2d95d706b4197cb952e89d0..4d4cec72212bda959b16c3f7f832afd2442c01f6 100644 --- a/include/opendht/crypto.h +++ b/include/opendht/crypto.h @@ -457,6 +457,29 @@ private: std::set<std::shared_ptr<RevocationList>, crlNumberCmp> revocation_lists; }; +struct OPENDHT_PUBLIC TrustList +{ + struct VerifyResult { + int ret; + unsigned result; + bool hasError() const { return ret < 0; } + bool isValid() const { return !hasError() and !(result & GNUTLS_CERT_INVALID); } + explicit operator bool() const { return isValid(); } + std::string toString() const; + OPENDHT_PUBLIC friend std::ostream& operator<< (std::ostream& s, const VerifyResult& h); + }; + + TrustList(); + ~TrustList(); + void add(const Certificate& crt); + void add(const RevocationList& crl); + void remove(const Certificate& crt, bool parents = true); + VerifyResult verify(const Certificate& crt) const; + +private: + gnutls_x509_trust_list_t trust; +}; + template <class T> class OPENDHT_PUBLIC secure_vector { diff --git a/src/crypto.cpp b/src/crypto.cpp index 2d292ca78831c976bf828c39281acde1eec72c25..c74d0cb162976bdd71750c893f5342e55843ccae 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -1172,5 +1172,95 @@ RevocationList::toString() const return ret; } +TrustList::TrustList() { + gnutls_x509_trust_list_init(&trust, 0); +} + +TrustList::~TrustList() { + gnutls_x509_trust_list_deinit(trust, 1); +} + +void TrustList::add(const Certificate& crt) +{ + auto chain = crt.getChainWithRevocations(true); + gnutls_x509_trust_list_add_cas(trust, chain.first.data(), chain.first.size(), GNUTLS_TL_NO_DUPLICATES); + if (not chain.second.empty()) + gnutls_x509_trust_list_add_crls( + trust, + chain.second.data(), chain.second.size(), + GNUTLS_TL_VERIFY_CRL | GNUTLS_TL_NO_DUPLICATES, 0); +} + +void TrustList::add(const RevocationList& crl) +{ + auto copy = crl.getCopy(); + gnutls_x509_trust_list_add_crls(trust, ©, 1, GNUTLS_TL_VERIFY_CRL | GNUTLS_TL_NO_DUPLICATES, 0); +} + +void TrustList::remove(const Certificate& crt, bool parents) +{ + gnutls_x509_trust_list_remove_cas(trust, &crt.cert, 1); + if (parents) { + for (auto c = crt.issuer; c; c = c->issuer) + gnutls_x509_trust_list_remove_cas(trust, &c->cert, 1); + } +} + +TrustList::VerifyResult +TrustList::verify(const Certificate& crt) const +{ + auto chain = crt.getChain(); + VerifyResult ret; + ret.ret = gnutls_x509_trust_list_verify_crt2( + trust, + chain.data(), chain.size(), + nullptr, 0, + GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_MEDIUM), + &ret.result, nullptr); + return ret; +} + +std::string +TrustList::VerifyResult::toString() const +{ + std::ostringstream ss; + ss << *this; + return ss.str(); +} + +std::ostream& operator<< (std::ostream& o, const TrustList::VerifyResult& h) +{ + if (h.ret < 0) { + o << "Error verifying certificate: " << gnutls_strerror(h.ret) << std::endl; + } else if (h.result & GNUTLS_CERT_INVALID) { + o << "Certificate check failed with code: " << h.result << std::endl; + if (h.result & GNUTLS_CERT_SIGNATURE_FAILURE) + o << "* The signature verification failed." << std::endl; + if (h.result & GNUTLS_CERT_REVOKED) + o << "* Certificate is revoked" << std::endl; + if (h.result & GNUTLS_CERT_SIGNER_NOT_FOUND) + o << "* Certificate's issuer is not known" << std::endl; + if (h.result & GNUTLS_CERT_SIGNER_NOT_CA) + o << "* Certificate's issuer not a CA" << std::endl; + if (h.result & GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE) + o << "* Certificate's signer constraints were violated" << std::endl; + if (h.result & GNUTLS_CERT_INSECURE_ALGORITHM) + o << "* Certificate was signed using an insecure algorithm" << std::endl; + if (h.result & GNUTLS_CERT_NOT_ACTIVATED) + o << "* Certificate is not yet activated" << std::endl; + if (h.result & GNUTLS_CERT_EXPIRED) + o << "* Certificate has expired" << std::endl; + if (h.result & GNUTLS_CERT_UNEXPECTED_OWNER) + o << "* The owner is not the expected one" << std::endl; + if (h.result & GNUTLS_CERT_PURPOSE_MISMATCH) + o << "* Certificate or an intermediate does not match the intended purpose" << std::endl; + if (h.result & GNUTLS_CERT_MISMATCH) + o << "* Certificate presented isn't the expected one" << std::endl; + } else { + o << "Certificate is valid" << std::endl; + } + return o; +} + } }