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(),