diff --git a/src/client/configurationmanager.cpp b/src/client/configurationmanager.cpp index a26184b704ab151b4db091cfb63294c9a6d0d589..a80ed0507482af860cc6fea427579f2e4feae65b 100644 --- a/src/client/configurationmanager.cpp +++ b/src/client/configurationmanager.cpp @@ -220,13 +220,8 @@ setCertificateStatus(const std::string& accountId, const std::string& certId, co if (accountId.empty()) { ring::tls::CertificateStore::instance().setTrustedCertificate(certId, ring::tls::trustStatusFromStr(ststr.c_str())); } else if (auto acc = ring::Manager::instance().getAccount<ring::RingAccount>(accountId)) { - try { - auto status = ring::tls::TrustStore::statusFromStr(ststr.c_str()); - return acc->setCertificateStatus(certId, status); - } catch (const std::out_of_range&) { - auto status = ring::tls::trustStatusFromStr(ststr.c_str()); - return acc->setCertificateStatus(certId, status); - } + auto status = ring::tls::TrustStore::statusFromStr(ststr.c_str()); + return acc->setCertificateStatus(certId, status); } } catch (const std::out_of_range&) {} return false; diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp index 3d902e48bfc7d5d836c11a4502180a229a39b7fb..ebb2b339fdac5d7ce1cb3dd2eccf29f3779aa4fe 100644 --- a/src/ringdht/ringaccount.cpp +++ b/src/ringdht/ringaccount.cpp @@ -191,9 +191,9 @@ struct RingAccount::Contact if (c.confirmed != confirmed) { confirmed = c.confirmed or confirmed; } - return hasSameState(copy); + return hasDifferentState(copy); } - bool hasSameState(const Contact& other) const { + bool hasDifferentState(const Contact& other) const { return other.isActive() != isActive() or other.isBanned() != isBanned() or other.confirmed != confirmed; @@ -798,8 +798,8 @@ RingAccount::createRingDevice(const dht::crypto::Identity& id) std::tie(tlsPrivateKeyFile_, tlsCertificateFile_) = saveIdentity(dev_id, idPath_, "ring_device"); tlsPassword_ = {}; identity_ = dev_id; - accountTrust_ = tls::TrustStore{}; - accountTrust_.setCertificateStatus(id.second, tls::TrustStore::PermissionStatus::ALLOWED, false); + accountTrust_ = dht::crypto::TrustList{}; + accountTrust_.add(*id.second); ringDeviceId_ = dev_id.first->getPublicKey().getId().toString(); ringDeviceName_ = ip_utils::getHostname(); if (ringDeviceName_.empty()) @@ -865,9 +865,9 @@ RingAccount::useIdentity(const dht::crypto::Identity& identity) } // match certificate chain - tls::TrustStore account_trust; - account_trust.setCertificateStatus(accountCertificate, tls::TrustStore::PermissionStatus::ALLOWED, false); - if (not account_trust.isAllowed(*identity.second)) { + dht::crypto::TrustList account_trust; + account_trust.add(*accountCertificate); + if (not account_trust.verify(*identity.second)) { RING_ERR("[Account %s] can't use identity: device certificate chain can't be verified", getAccountID().c_str()); return false; } @@ -2304,6 +2304,9 @@ RingAccount::onTrustRequest(const dht::InfoHash& peer_account, const dht::InfoHa // Check existing contact auto contact = contacts_.find(peer_account); if (contact != contacts_.end()) { + // Banned contact: discard request + if (contact->second.isBanned()) + return; // Send confirmation if (not confirm) sendTrustRequestConfirm(peer_account); @@ -2343,16 +2346,16 @@ RingAccount::onTrustRequest(const dht::InfoHash& peer_account, const dht::InfoHa void RingAccount::onPeerMessage(const dht::InfoHash& peer_device, std::function<void(const std::shared_ptr<dht::crypto::Certificate>& crt, const dht::InfoHash& peer_account)> cb) { - // quick check in case we already explicilty banned this public key + // quick check in case we already explicilty banned this device auto trustStatus = trust_.getCertificateStatus(peer_device.toString()); if (trustStatus == tls::TrustStore::PermissionStatus::BANNED) { - RING_WARN("[Account %s] Discarding message from banned peer %s", getAccountID().c_str(), peer_device.toString().c_str()); + RING_WARN("[Account %s] Discarding message from banned device %s", getAccountID().c_str(), peer_device.toString().c_str()); return; } auto shared = std::static_pointer_cast<RingAccount>(shared_from_this()); findCertificate(peer_device, - [shared, peer_device, trustStatus, cb](const std::shared_ptr<dht::crypto::Certificate>& cert) { + [shared, peer_device, cb](const std::shared_ptr<dht::crypto::Certificate>& cert) { auto& this_ = *shared; dht::InfoHash peer_account_id; @@ -2361,19 +2364,8 @@ RingAccount::onPeerMessage(const dht::InfoHash& peer_device, std::function<void( return; } - if (not this_.dhtPublicInCalls_ and trustStatus != tls::TrustStore::PermissionStatus::ALLOWED) { - if (!cert or cert->getId() != peer_device) { - RING_WARN("[Account %s] Can't find certificate of %s for incoming message.", this_.getAccountID().c_str(), peer_device.toString().c_str()); - return; - } - - auto& this_ = *shared; - if (!this_.trust_.isAllowed(*cert)) { - RING_WARN("[Account %s] Discarding message from untrusted peer %s.", this_.getAccountID().c_str(), peer_device.toString().c_str()); - return; - } - } else if (not this_.dhtPublicInCalls_ or trustStatus == tls::TrustStore::PermissionStatus::BANNED) { - RING_WARN("[Account %s] Discarding message from untrusted or banned peer %s.", this_.getAccountID().c_str(), peer_device.toString().c_str()); + if (not this_.trust_.isAllowed(*cert, this_.dhtPublicInCalls_)) { + RING_WARN("[Account %s] Discarding message from unauthorized peer %s.", this_.getAccountID().c_str(), peer_device.toString().c_str()); return; } @@ -2421,7 +2413,7 @@ RingAccount::foundAccountDevice(const std::shared_ptr<dht::crypto::Certificate>& return false; // match certificate chain - if (not accountTrust_.isAllowed(*crt)) { + if (not accountTrust_.verify(*crt)) { RING_WARN("[Account %s] Found invalid account device: %s", getAccountID().c_str(), crt->getId().toString().c_str()); return false; } @@ -2465,19 +2457,17 @@ RingAccount::foundPeerDevice(const std::shared_ptr<dht::crypto::Certificate>& cr return false; } - RING_WARN("foundPeerDevice dev:%s CA:%s", crt->getId().toString().c_str(), top_issuer->getId().toString().c_str()); - // Check peer certificate chain // Trust store with top issuer as the only CA - tls::TrustStore peer_trust; - peer_trust.setCertificateStatus(top_issuer, tls::TrustStore::PermissionStatus::ALLOWED, false); - - if (not peer_trust.isAllowed(*crt)) { + dht::crypto::TrustList peer_trust; + peer_trust.add(*top_issuer); + if (not peer_trust.verify(*crt)) { RING_WARN("[Account %s] Found invalid peer device: %s", getAccountID().c_str(), crt->getId().toString().c_str()); return false; } account_id = crt->issuer->getId(); + RING_WARN("[Account %s] found peer device: %s account:%s CA:%s", getAccountID().c_str(), crt->getId().toString().c_str(), account_id.toString().c_str(), top_issuer->getId().toString().c_str()); return true; } @@ -2622,16 +2612,6 @@ RingAccount::setCertificateStatus(const std::string& cert_id, tls::TrustStore::P return done; } -bool -RingAccount::setCertificateStatus(const std::string& cert_id, tls::TrustStatus status) -{ - findCertificate(cert_id); - bool done = trust_.setCertificateStatus(cert_id, status); - if (done) - emitSignal<DRing::ConfigurationSignal::CertificateStateChanged>(getAccountID(), cert_id, tls::statusToStr(status)); - return done; -} - std::vector<std::string> RingAccount::getCertificatesByStatus(tls::TrustStore::PermissionStatus status) { @@ -2917,6 +2897,7 @@ RingAccount::getContactHeader(pjsip_transport* t) void RingAccount::addContact(const std::string& uri, bool confirmed) { + RING_WARN("[Account %s] addContact: %s", getAccountID().c_str(), uri.c_str()); dht::InfoHash h (uri); auto c = contacts_.find(h); if (c == contacts_.end()) @@ -2934,6 +2915,7 @@ RingAccount::addContact(const std::string& uri, bool confirmed) void RingAccount::removeContact(const std::string& uri, bool ban) { + RING_WARN("[Account %s] removeContact: %s", getAccountID().c_str(), uri.c_str()); dht::InfoHash h (uri); auto c = contacts_.find(h); if (c == contacts_.end()) @@ -2942,8 +2924,10 @@ RingAccount::removeContact(const std::string& uri, bool ban) return; c->second.removed = std::time(nullptr); c->second.banned = ban; - if (ban) - trust_.setCertificateStatus(uri, tls::TrustStore::PermissionStatus::BANNED); + trust_.setCertificateStatus(uri, ban ? tls::TrustStore::PermissionStatus::BANNED + : tls::TrustStore::PermissionStatus::UNDEFINED); + if (ban and trustRequests_.erase(h) > 0) + saveTrustRequests(); saveContacts(); emitSignal<DRing::ConfigurationSignal::ContactRemoved>(getAccountID(), uri, ban); syncDevices(); diff --git a/src/ringdht/ringaccount.h b/src/ringdht/ringaccount.h index f8a3dd9b822c2b6b3ea3597c6529b50b0791e0ea..694f4894c67ca53e4d2c00da495a0ac8d905b1de 100644 --- a/src/ringdht/ringaccount.h +++ b/src/ringdht/ringaccount.h @@ -279,7 +279,6 @@ class RingAccount : public SIPAccountBase { } bool setCertificateStatus(const std::string& cert_id, tls::TrustStore::PermissionStatus status); - bool setCertificateStatus(const std::string& cert_id, tls::TrustStatus status); std::vector<std::string> getCertificatesByStatus(tls::TrustStore::PermissionStatus status); @@ -477,7 +476,7 @@ class RingAccount : public SIPAccountBase { void updateContact(const dht::InfoHash&, const Contact&); // Trust store with Ring account main certificate as the only CA - tls::TrustStore accountTrust_; + dht::crypto::TrustList accountTrust_; // Trust store for to match peer certificates tls::TrustStore trust_; diff --git a/src/security/certstore.cpp b/src/security/certstore.cpp index f4e89ddab9898dc82bf674fb1a6fe7b45dc90c54..9985bc72393fe77235abd81d3bd9fee50181e330 100644 --- a/src/security/certstore.cpp +++ b/src/security/certstore.cpp @@ -402,101 +402,70 @@ statusToStr(TrustStatus s) } } -TrustStore::TrustStore() -{ - gnutls_x509_trust_list_init(&allowed_, 0); -} - -TrustStore::~TrustStore() -{ - gnutls_x509_trust_list_deinit(allowed_, true); -} - -TrustStore& -TrustStore::operator=(TrustStore&& o) -{ - unknownCertStatus_ = std::move(o.unknownCertStatus_); - certStatus_ = std::move(o.certStatus_); - revokedList_ = std::move(o.revokedList_); - if (allowed_) - gnutls_x509_trust_list_deinit(allowed_, true); - allowed_ = std::move(o.allowed_); - o.allowed_ = nullptr; - return *this; -} - bool TrustStore::addRevocationList(dht::crypto::RevocationList&& crl) { - auto packed = crl.getPacked(); - revokedList_.emplace_back(std::forward<dht::crypto::RevocationList>(crl)); - auto crlp = crl.get(); - return gnutls_x509_trust_list_add_crls(allowed_, &crlp, 1, GNUTLS_TL_VERIFY_CRL, 0) > 0; + allowed_.add(crl); + return true; } bool TrustStore::setCertificateStatus(const std::string& cert_id, const TrustStore::PermissionStatus status) { - updateKnownCerts(); - auto s = certStatus_.find(cert_id); - if (s == std::end(certStatus_)) { - if (auto cert = CertificateStore::instance().getCertificate(cert_id)) { - auto& crt_status = certStatus_[cert->getId().toString()]; - if (not crt_status.first) - crt_status.first = cert; - crt_status.second.allowed = (status == PermissionStatus::ALLOWED); - setStoreCertStatus(*cert, status); - } else - unknownCertStatus_[cert_id].allowed = (status == PermissionStatus::ALLOWED); - } else { - s->second.second.allowed = (status == PermissionStatus::ALLOWED); - setStoreCertStatus(*s->second.first, status); - } - return true; + return setCertificateStatus(nullptr, cert_id, status, false); } bool TrustStore::setCertificateStatus(const std::shared_ptr<crypto::Certificate>& cert, const TrustStore::PermissionStatus status, bool local) { - CertificateStore::instance().pinCertificate(cert, local); - auto& crt_status = certStatus_[cert->getId().toString()]; - if (not crt_status.first) - crt_status.first = cert; - crt_status.second.allowed = (status == PermissionStatus::ALLOWED); - setStoreCertStatus(*cert, status); - return true; + return setCertificateStatus(cert, cert->getId().toString(), status, local); } bool -TrustStore::setCertificateStatus(const std::string& cert_id, const TrustStatus status) +TrustStore::setCertificateStatus(std::shared_ptr<crypto::Certificate> cert, + const std::string& cert_id, + const TrustStore::PermissionStatus status, bool local) { + if (cert) + CertificateStore::instance().pinCertificate(cert, local); updateKnownCerts(); - auto s = certStatus_.find(cert_id); - if (s == std::end(certStatus_)) { - if (auto cert = CertificateStore::instance().getCertificate(cert_id)) { - auto& crt_status = certStatus_[cert->getId().toString()]; - if (not crt_status.first) - crt_status.first = cert; - crt_status.second.trusted = (status == TrustStatus::TRUSTED); - } else - unknownCertStatus_[cert_id].trusted = (status == TrustStatus::TRUSTED); + bool dirty {false}; + if (status == PermissionStatus::UNDEFINED) { + unknownCertStatus_.erase(cert_id); + dirty = certStatus_.erase(cert_id); } else { - s->second.second.trusted = (status == TrustStatus::TRUSTED); + bool allowed = (status == PermissionStatus::ALLOWED); + auto s = certStatus_.find(cert_id); + if (s == std::end(certStatus_)) { + // Certificate state is currently undefined + if (not cert) + cert = CertificateStore::instance().getCertificate(cert_id); + if (cert) { + unknownCertStatus_.erase(cert_id); + auto& crt_status = certStatus_[cert_id]; + if (not crt_status.first) + crt_status.first = cert; + crt_status.second.allowed = allowed; + setStoreCertStatus(*cert, allowed); + } else { + // Can't find certificate + unknownCertStatus_[cert_id].allowed = allowed; + } + } else { + // Certificate is already allowed or banned + if (s->second.second.allowed != allowed) { + s->second.second.allowed = allowed; + if (allowed) // Certificate is re-added after ban, rebuld needed + dirty = true; + else + allowed_.remove(*s->second.first); + } + } } - return true; -} - -bool -TrustStore::setCertificateStatus(const std::shared_ptr<crypto::Certificate>& cert, - const TrustStatus status, bool local) -{ - CertificateStore::instance().pinCertificate(cert, local); - auto& crt_status = certStatus_[cert->getId().toString()]; - if (not crt_status.first) - crt_status.first = cert; - crt_status.second.trusted = (status == TrustStatus::TRUSTED); + if (dirty) + rebuildTrust(); return true; } @@ -513,19 +482,6 @@ TrustStore::getCertificateStatus(const std::string& cert_id) const return s->second.second.allowed ? PermissionStatus::ALLOWED : PermissionStatus::BANNED; } -TrustStatus -TrustStore::getCertificateTrustStatus(const std::string& cert_id) const -{ - auto s = certStatus_.find(cert_id); - if (s == std::end(certStatus_)) { - auto us = unknownCertStatus_.find(cert_id); - if (us == std::end(unknownCertStatus_)) - return TrustStatus::UNTRUSTED; - return us->second.trusted ? TrustStatus::TRUSTED : TrustStatus::UNTRUSTED; - } - return s->second.second.trusted ? TrustStatus::TRUSTED : TrustStatus::UNTRUSTED; -} - std::vector<std::string> TrustStore::getCertificatesByStatus(TrustStore::PermissionStatus status) { @@ -540,104 +496,27 @@ TrustStore::getCertificatesByStatus(TrustStore::PermissionStatus status) } bool -TrustStore::isAllowed(const crypto::Certificate& crt) -{ - // Match by certificate pinning (device) - auto status = getCertificateStatus(crt.getId().toString()); - if (status == PermissionStatus::ALLOWED) - return true; - else if (status == PermissionStatus::BANNED) - return false; +TrustStore::isAllowed(const crypto::Certificate& crt, bool allowPublic) +{ + // Match by certificate pinning + bool allowed {allowPublic}; + for (auto c = &crt; c; c = c->issuer.get()) { + auto status = getCertificateStatus(c->getId().toString()); + if (status == PermissionStatus::ALLOWED) + allowed = true; + else if (status == PermissionStatus::BANNED) + return false; + } // Match by certificate chain updateKnownCerts(); - return matchTrustStore(getChain(crt), allowed_); -} - - -std::vector<gnutls_x509_crt_t> -TrustStore::getTrustedCertificates() const -{ - auto cas = CertificateStore::instance().getTrustedCertificates(); - for (const auto& i : certStatus_) - if (i.second.second.trusted) - cas.emplace_back(i.second.first->cert); - return cas; -} - -bool -TrustStore::matchTrustStore(std::vector<gnutls_x509_crt_t>&& crts, gnutls_x509_trust_list_st* store) -{ - unsigned result = 0; - -#if GNUTLS_VERSION_NUMBER > 0x030308 - auto ret = gnutls_x509_trust_list_verify_crt2( - store, - crts.data(), crts.size(), - nullptr, 0, - GNUTLS_PROFILE_TO_VFLAGS(GNUTLS_PROFILE_MEDIUM), - &result, nullptr); -#else - auto ret = gnutls_x509_trust_list_verify_crt( - store, - crts.data(), crts.size(), - 0, - &result, nullptr); -#endif - - if (ret < 0) { - RING_ERR("Error verifying certificate: %s", gnutls_strerror(ret)); + auto ret = allowed_.verify(crt); + if (not ret) { + RING_WARN("%s", ret.toString().c_str()); return false; - } else if (result & GNUTLS_CERT_INVALID) { - RING_WARN("Certificate check failed with code: %d", result); - if (result & GNUTLS_CERT_SIGNATURE_FAILURE) - RING_WARN("* The signature verification failed."); - if (result & GNUTLS_CERT_REVOKED) - RING_WARN("* Certificate is revoked"); - if (result & GNUTLS_CERT_SIGNER_NOT_FOUND) - RING_WARN("* Certificate's issuer is not known"); - if (result & GNUTLS_CERT_SIGNER_NOT_CA) - RING_WARN("* Certificate's issuer not a CA"); - if (result & GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE) - RING_WARN("* Certificate's signer constraints were violated"); - if (result & GNUTLS_CERT_INSECURE_ALGORITHM) - RING_WARN("* Certificate was signed using an insecure algorithm"); - if (result & GNUTLS_CERT_NOT_ACTIVATED) - RING_WARN("* Certificate is not yet activated"); - if (result & GNUTLS_CERT_EXPIRED) - RING_WARN("* Certificate has expired"); - if (result & GNUTLS_CERT_UNEXPECTED_OWNER) - RING_WARN("* The owner is not the expected one"); - if (result & GNUTLS_CERT_PURPOSE_MISMATCH) - RING_WARN("* Certificate or an intermediate does not match the intended purpose"); - if (result & GNUTLS_CERT_MISMATCH) - RING_WARN("* Certificate presented isn't the expected one"); } - return !(result & GNUTLS_CERT_INVALID); -} - -std::vector<gnutls_x509_crt_t> -getChain(const crypto::Certificate& crt, bool copy) -{ - std::vector<gnutls_x509_crt_t> crts; - auto c = &crt; - do { - crts.emplace_back(copy ? c->getCopy() : c->cert); - c = c->issuer.get(); - } while (c); - return crts; -} - -std::vector<gnutls_x509_crl_t> -getRevocationList(const crypto::Certificate& crt) -{ - std::vector<gnutls_x509_crl_t> crls_ret; - const auto& crls = crt.getRevocationLists(); - crls_ret.reserve(crls.size()); - for (const auto& crl : crls) - crls_ret.emplace_back(crl->getCopy()); - return crls_ret; + return allowed; } void @@ -647,7 +526,7 @@ TrustStore::updateKnownCerts() while (i != std::end(unknownCertStatus_)) { if (auto crt = CertificateStore::instance().getCertificate(i->first)) { certStatus_.emplace(i->first, std::make_pair(crt, i->second)); - setStoreCertStatus(*crt, i->second.allowed ? PermissionStatus::ALLOWED : PermissionStatus::UNDEFINED); + setStoreCertStatus(*crt, i->second.allowed); i = unknownCertStatus_.erase(i); } else ++i; @@ -655,28 +534,20 @@ TrustStore::updateKnownCerts() } void -TrustStore::setStoreCertStatus(const crypto::Certificate& crt, TrustStore::PermissionStatus status) -{ - if (not crt.isCA()) - return; - - if (status == PermissionStatus::ALLOWED) { - auto crt_copy = getChain(crt, true); - gnutls_x509_trust_list_add_cas(allowed_, crt_copy.data(), crt_copy.size(), GNUTLS_TL_NO_DUPLICATES); - auto crls = getRevocationList(crt); - if (not crls.empty()) - if (gnutls_x509_trust_list_add_crls( - allowed_, - crls.data(), crls.size(), - GNUTLS_TL_VERIFY_CRL | GNUTLS_TL_NO_DUPLICATES, 0) == 0) - RING_WARN("No CRLs where added"); - } +TrustStore::setStoreCertStatus(const crypto::Certificate& crt, bool status) +{ + if (status) + allowed_.add(crt); else - gnutls_x509_trust_list_remove_cas(allowed_, &crt.cert, 1); + allowed_.remove(crt); +} - RING_DBG("TrustStore: setting %s status to %s.", - crt.getId().toString().c_str(), - status == PermissionStatus::ALLOWED ? "ALLOWED" : "NOT ALLOWED"); +void +TrustStore::rebuildTrust() +{ + allowed_ = {}; + for (const auto& c : certStatus_) + setStoreCertStatus(*c.second.first, c.second.second.allowed); } }} // namespace ring::tls diff --git a/src/security/certstore.h b/src/security/certstore.h index 9e8183473a9ca1a5d7a839622fc67a24699b24c1..b3aa7757116fe33a8e5501179a76c0cf556fbebd 100644 --- a/src/security/certstore.h +++ b/src/security/certstore.h @@ -32,8 +32,6 @@ #include <future> #include <mutex> -struct gnutls_x509_trust_list_st; - namespace ring { namespace tls { namespace crypto = dht::crypto; @@ -108,18 +106,9 @@ private: */ class TrustStore { public: - TrustStore(); - virtual ~TrustStore(); - TrustStore(TrustStore&& o) : - unknownCertStatus_(std::move(o.unknownCertStatus_)), - certStatus_(std::move(o.certStatus_)), - revokedList_(std::move(o.revokedList_)), - allowed_(std::move(o.allowed_)) - { - o.allowed_ = nullptr; - } - - TrustStore& operator=(TrustStore&& o); + TrustStore() = default; + TrustStore(TrustStore&& o) = default; + TrustStore& operator=(TrustStore&& o) = default; enum class PermissionStatus { UNDEFINED = 0, @@ -135,39 +124,43 @@ public: bool setCertificateStatus(const std::string& cert_id, const PermissionStatus status); bool setCertificateStatus(const std::shared_ptr<crypto::Certificate>& cert, PermissionStatus status, bool local = true); - bool setCertificateStatus(const std::string& cert_id, const TrustStatus status); - bool setCertificateStatus(const std::shared_ptr<crypto::Certificate>& cert, TrustStatus status, bool local = true); - PermissionStatus getCertificateStatus(const std::string& cert_id) const; - TrustStatus getCertificateTrustStatus(const std::string& cert_id) const; std::vector<std::string> getCertificatesByStatus(PermissionStatus status); - bool isAllowed(const crypto::Certificate& crt); - - std::vector<gnutls_x509_crt_t> getTrustedCertificates() const; + /** + * Check that the certificate is allowed (valid and permited) for contact. + * Valid means the certificate chain matches with our CA list, + * has valid signatures, expiration dates etc. + * Permited means at least one of the certificate in the chain is + * ALLOWED (if allowPublic is false), and none is BANNED. + * + * @param crt the end certificate of the chain to check + * @param allowPublic if false, requires at least one ALLOWED certificate. + * (not required otherwise). In any case a BANNED + * certificate means permission refusal. + * @return true if the certificate is valid and permitted. + */ + bool isAllowed(const crypto::Certificate& crt, bool allowPublic = false); private: NON_COPYABLE(TrustStore); void updateKnownCerts(); - void setStoreCertStatus(const crypto::Certificate& crt, PermissionStatus status); - - static bool matchTrustStore(std::vector<gnutls_x509_crt_t>&& crts, gnutls_x509_trust_list_st* store); + bool setCertificateStatus(std::shared_ptr<crypto::Certificate> cert, + const std::string& cert_id, + const TrustStore::PermissionStatus status, bool local); + void setStoreCertStatus(const crypto::Certificate& crt, bool status); + void rebuildTrust(); struct Status { - bool allowed : 1; - bool trusted : 1; + bool allowed; }; // unknown certificates with known status std::map<std::string, Status> unknownCertStatus_; std::map<std::string, std::pair<std::shared_ptr<crypto::Certificate>, Status>> certStatus_; - std::vector<dht::crypto::RevocationList> revokedList_; - gnutls_x509_trust_list_st* allowed_; + dht::crypto::TrustList allowed_; }; -std::vector<gnutls_x509_crt_t> getChain(const crypto::Certificate& crt, bool copy = false); -std::vector<gnutls_x509_crl_t> getRevocationList(const crypto::Certificate& crt); - }} // namespace ring::tls diff --git a/src/security/tlsvalidator.cpp b/src/security/tlsvalidator.cpp index 9af465942d7e53a44bfbd9a24546d13ddd2c3f84..ccccb9a31b76c171a9ba071a76a40e14a135e966 100644 --- a/src/security/tlsvalidator.cpp +++ b/src/security/tlsvalidator.cpp @@ -447,9 +447,6 @@ unsigned int TlsValidator::compareToCa() if (caChecked_) return caValidationOutput_; - // build the certificate chain - auto crts = getChain(*x509crt_); - // build the CA trusted list gnutls_x509_trust_list_t trust; gnutls_x509_trust_list_init(&trust, 0); @@ -466,6 +463,8 @@ unsigned int TlsValidator::compareToCa() gnutls_x509_trust_list_add_trust_file(trust, caListPath_.c_str(), nullptr, GNUTLS_X509_FMT_PEM, 0, 0); } + // build the certificate chain + auto crts = x509crt_->getChain(); err = gnutls_x509_trust_list_verify_crt2( trust, crts.data(), crts.size(),