certstore: follow chain for getCertificateStatus

If a certificate is banned in the trust store, every signed child
certificate should be banned too.

Change-Id: I13cf12ce12c7c94886a5d7b909325857ad01c9a9
diff --git a/src/security/certstore.cpp b/src/security/certstore.cpp
index e58b288..a3d72c9 100644
--- a/src/security/certstore.cpp
+++ b/src/security/certstore.cpp
@@ -600,14 +600,36 @@
 TrustStore::getCertificateStatus(const std::string& cert_id) const
 {
     std::lock_guard<std::recursive_mutex> lk(mutex_);
-    auto s = certStatus_.find(cert_id);
-    if (s == std::end(certStatus_)) {
-        auto us = unknownCertStatus_.find(cert_id);
-        if (us == std::end(unknownCertStatus_))
-            return PermissionStatus::UNDEFINED;
-        return us->second.allowed ? PermissionStatus::ALLOWED : PermissionStatus::BANNED;
+    auto cert = certStore_.getCertificate(cert_id);
+    if (!cert)
+        return PermissionStatus::UNDEFINED;
+    auto allowed = false; auto found = false;
+    while (cert) {
+        auto s = certStatus_.find(cert->getId().toString());
+        if (s != std::end(certStatus_)) {
+            if (!found) {
+                found = true; allowed = true; // we need to find at least a certificate
+            }
+            allowed &= s->second.second.allowed;
+            if (!allowed)
+                return PermissionStatus::BANNED;
+        } else {
+            auto us = unknownCertStatus_.find(cert->getId().toString());
+            if (us != std::end(unknownCertStatus_)) {
+                if (!found) {
+                    found = true; allowed = true; // we need to find at least a certificate
+                }
+                allowed &= s->second.second.allowed;
+                if (!us->second.allowed)
+                    return PermissionStatus::BANNED;
+            }
+        }
+        if (cert->getUID() == cert->getIssuerUID())
+            break;
+        cert = cert->issuer? cert->issuer : certStore_.getCertificate(cert->getIssuerUID());
     }
-    return s->second.second.allowed ? PermissionStatus::ALLOWED : PermissionStatus::BANNED;
+
+    return allowed? PermissionStatus::ALLOWED : PermissionStatus::UNDEFINED;
 }
 
 std::vector<std::string>
diff --git a/tests/certstore.cpp b/tests/certstore.cpp
index 0bc7722..9f4fc81 100644
--- a/tests/certstore.cpp
+++ b/tests/certstore.cpp
@@ -41,10 +41,12 @@
 private:
     void trustStoreTest();
     void getCertificateWithSplitted();
+    void testBannedParent();
 
     CPPUNIT_TEST_SUITE(CertStoreTest);
     CPPUNIT_TEST(trustStoreTest);
     CPPUNIT_TEST(getCertificateWithSplitted);
+    CPPUNIT_TEST(testBannedParent);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -199,6 +201,30 @@
                    && fullCert->issuer->issuer->getUID() == caCert->getUID());*/
 }
 
+void
+CertStoreTest::testBannedParent()
+{
+    /*auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
+
+    auto ca = dht::crypto::generateIdentity("test CA");
+    auto account = dht::crypto::generateIdentity("test account", ca, 4096, true);
+    auto device = dht::crypto::generateIdentity("test device", account);
+    auto device2 = dht::crypto::generateIdentity("test device 2", account);
+    auto id = ca.second->getId().toString();
+    auto pinned = aliceAccount->certStore().getPinnedCertificates();
+    CPPUNIT_ASSERT(std::find_if(pinned.begin(), pinned.end(), [&](auto v) { return v == id; })
+                   == pinned.end());
+
+    // Ban account
+    aliceAccount->setCertificateStatus(account.second, dhtnet::tls::TrustStore::PermissionStatus::BANNED);
+    CPPUNIT_ASSERT(aliceAccount->accountManager()->getCertificateStatus(account.second->getId().toString())
+                   == dhtnet::tls::TrustStore::PermissionStatus::BANNED);
+    CPPUNIT_ASSERT(not aliceAccount->accountManager()->isAllowed(*account.second));
+    CPPUNIT_ASSERT(not aliceAccount->accountManager()->isAllowed(*device2.second));
+    CPPUNIT_ASSERT(not aliceAccount->accountManager()->isAllowed(*device.second));*/
+}
+
+
 } // namespace test
 } // namespace dhtnet