Add end to end tests for CertBlacklist functionality

This adds a test public key to the default list of blacklisted CAs
(private key in src/test/resources/blacklist_ca_key.pem) and adds a
number of end to end tests that TrustManagerImpl enforces blacklists in
chains. This test key will also be used by CTS to ensure that the
default X509TrustManager properly enforces the blacklist.

(cherry picked from commit 1c4c0a23e4cd4f99e87ee770ea462c6351152c13)
Bug: 29443053
Change-Id: I67dcb7ef8da490544791a4c90c74ffa7582a1826
diff --git a/src/platform/java/org/conscrypt/CertBlacklist.java b/src/platform/java/org/conscrypt/CertBlacklist.java
index 56ddb65..d49ab15 100644
--- a/src/platform/java/org/conscrypt/CertBlacklist.java
+++ b/src/platform/java/org/conscrypt/CertBlacklist.java
@@ -35,24 +35,26 @@
 public class CertBlacklist {
     private static final Logger logger = Logger.getLogger(CertBlacklist.class.getName());
 
-    // public for testing
-    public final Set<BigInteger> serialBlacklist;
-    public final Set<byte[]> pubkeyBlacklist;
+    private final Set<BigInteger> serialBlacklist;
+    private final Set<byte[]> pubkeyBlacklist;
 
-    public CertBlacklist() {
+    /**
+     * public for testing only.
+     */
+    public CertBlacklist(Set<BigInteger> serialBlacklist, Set<byte[]> pubkeyBlacklist) {
+        this.serialBlacklist = serialBlacklist;
+        this.pubkeyBlacklist = pubkeyBlacklist;
+    }
+
+    public static CertBlacklist getDefault() {
         String androidData = System.getenv("ANDROID_DATA");
         String blacklistRoot = androidData + "/misc/keychain/";
         String defaultPubkeyBlacklistPath = blacklistRoot + "pubkey_blacklist.txt";
         String defaultSerialBlacklistPath = blacklistRoot + "serial_blacklist.txt";
 
-        pubkeyBlacklist = readPublicKeyBlackList(defaultPubkeyBlacklistPath);
-        serialBlacklist = readSerialBlackList(defaultSerialBlacklistPath);
-    }
-
-    /** Test only interface, not for public use */
-    public CertBlacklist(String pubkeyBlacklistPath, String serialBlacklistPath) {
-        pubkeyBlacklist = readPublicKeyBlackList(pubkeyBlacklistPath);
-        serialBlacklist = readSerialBlackList(serialBlacklistPath);
+        Set<byte[]> pubkeyBlacklist = readPublicKeyBlackList(defaultPubkeyBlacklistPath);
+        Set<BigInteger> serialBlacklist = readSerialBlackList(defaultSerialBlacklistPath);
+        return new CertBlacklist(serialBlacklist, pubkeyBlacklist);
     }
 
     private static boolean isHex(String value) {
@@ -165,6 +167,10 @@
 
         // start out with a base set of known bad values
         Set<byte[]> bl = new HashSet<byte[]>(Arrays.asList(
+            // Blacklist test cert for CTS. The cert and key can be found in
+            // src/test/resources/blacklist_test_ca.pem and
+            // src/test/resources/blacklist_test_ca_key.pem.
+            "bae78e6bed65a2bf60ddedde7fd91e825865e93d".getBytes(),
             // From http://src.chromium.org/viewvc/chrome/branches/782/src/net/base/x509_certificate.cc?r1=98750&r2=98749&pathrev=98750
             // C=NL, O=DigiNotar, CN=DigiNotar Root CA/emailAddress=info@diginotar.nl
             "410f36363258f30b347d12ce4863e433437806a8".getBytes(),
diff --git a/src/platform/java/org/conscrypt/TrustManagerImpl.java b/src/platform/java/org/conscrypt/TrustManagerImpl.java
index bebaaf7..57b222a 100644
--- a/src/platform/java/org/conscrypt/TrustManagerImpl.java
+++ b/src/platform/java/org/conscrypt/TrustManagerImpl.java
@@ -180,7 +180,7 @@
         }
 
         if (blacklist == null) {
-            blacklist = new CertBlacklist();
+            blacklist = CertBlacklist.getDefault();
         }
 
         this.rootKeyStore = rootKeyStoreLocal;
diff --git a/src/test/java/org/conscrypt/CertBlacklistTest.java b/src/test/java/org/conscrypt/CertBlacklistTest.java
new file mode 100644
index 0000000..3075726
--- /dev/null
+++ b/src/test/java/org/conscrypt/CertBlacklistTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.conscrypt;
+
+import java.io.InputStream;
+import java.util.Collection;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+import junit.framework.TestCase;
+
+public class CertBlacklistTest extends TestCase {
+
+    private static final String BLACKLIST_CA = "test_blacklist_ca.pem";
+    private static final String BLACKLISTED_CHAIN = "blacklist_test_chain.pem";
+    private static final String BLACKLIST_FALLBACK_VALID_CA = "blacklist_test_valid_ca.pem";
+    private static final String BLACKLISTED_VALID_CHAIN = "blacklist_test_valid_chain.pem";
+
+    /**
+     * Ensure that the test blacklisted CA is actually blacklisted by default.
+     */
+    public void testBlacklistedPublicKey() throws Exception {
+        X509Certificate blacklistedCa = loadCertificate(BLACKLIST_CA);
+        CertBlacklist blacklist = CertBlacklist.getDefault();
+        assertTrue(blacklist.isPublicKeyBlackListed(blacklistedCa.getPublicKey()));
+    }
+
+    /**
+     * Check that the blacklisted CA is rejected even if it used as a root of trust
+     */
+    public void testBlacklistedCaUntrusted() throws Exception {
+        X509Certificate blacklistedCa = loadCertificate(BLACKLIST_CA);
+        assertUntrusted(new X509Certificate[] {blacklistedCa}, getTrustManager(blacklistedCa));
+    }
+
+    /**
+     * Check that a chain that is rooted in a blacklisted trusted CA is rejected.
+     */
+    public void testBlacklistedRootOfTrust() throws Exception {
+        // Chain is leaf -> blacklisted
+        X509Certificate[] chain = loadCertificates(BLACKLISTED_CHAIN);
+        X509Certificate blacklistedCa = loadCertificate(BLACKLIST_CA);
+        assertUntrusted(chain, getTrustManager(blacklistedCa));
+    }
+
+    /** Test that the path building correctly routes around a blacklisted cert where there are
+     * other valid paths available. This prevents breakage where a cert was cross signed by a
+     * blacklisted CA but is still valid due to also being cross signed by CAs that remain trusted.
+     * Path:
+     *
+     * leaf -> intermediate -> blacklisted_ca
+     *               \
+     *                -------> trusted_ca
+     */
+    public void testBlacklistedIntermediateFallback() throws Exception {
+        X509Certificate[] chain = loadCertificates(BLACKLISTED_VALID_CHAIN);
+        X509Certificate blacklistedCa = loadCertificate(BLACKLIST_CA);
+        X509Certificate validCa = loadCertificate(BLACKLIST_FALLBACK_VALID_CA);
+        assertTrusted(chain, getTrustManager(blacklistedCa, validCa));
+        // Check that without the trusted_ca the chain is invalid (since it only chains to a
+        // blacklisted ca)
+        assertUntrusted(chain, getTrustManager(blacklistedCa));
+    }
+
+    private static X509Certificate loadCertificate(String file) throws Exception {
+        return loadCertificates(file)[0];
+    }
+
+    private static X509Certificate[] loadCertificates(String file) throws Exception {
+        CertificateFactory factory = CertificateFactory.getInstance("X.509");
+        try (InputStream is = TestUtils.openTestFile(file)) {
+            Collection<? extends Certificate> collection = factory.generateCertificates(is);
+            is.close();
+            X509Certificate[] certs = new X509Certificate[collection.size()];
+            int i = 0;
+            for (Certificate cert : collection) {
+                certs[i++] = (X509Certificate) cert;
+            }
+            return certs;
+        }
+    }
+
+    private static TrustManagerImpl getTrustManager(X509Certificate... trustedCas)
+            throws Exception {
+        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+        ks.load(null);
+        int i = 0;
+        for (X509Certificate ca : trustedCas) {
+            ks.setCertificateEntry(String.valueOf(i++), ca);
+        }
+        return new TrustManagerImpl(ks);
+    }
+
+    private static void assertTrusted(X509Certificate[] certs, X509TrustManager tm)
+            throws Exception {
+        tm.checkServerTrusted(certs, "RSA");
+    }
+
+    private static void assertUntrusted(X509Certificate[] certs, X509TrustManager tm) {
+        try {
+            tm.checkServerTrusted(certs, "RSA");
+            fail();
+        } catch (CertificateException expected) {
+        }
+    }
+}
diff --git a/src/test/resources/blacklist_test_chain.pem b/src/test/resources/blacklist_test_chain.pem
new file mode 100644
index 0000000..6f1f297
--- /dev/null
+++ b/src/test/resources/blacklist_test_chain.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIICxzCCAa+gAwIBAgIDAopPMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNVBAMTEWJs
+YWNrbGlzdCB0ZXN0IENBMCoYEzIwMTUwMTAxMDAwMDAwKzAwMDAYEzIwMjUwMTAx
+MDAwMDAwKzAwMDAwDzENMAsGA1UEAxMEbGVhZjCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAOA1rNFofKivnO6f/UjNnkUZX4qG+MBXw5eeingfrLrAbyTP
+qf/YCN3F8JOcot1QUEojcjIrm54rDgi1+o9qDDY0CfbJ8UGmjgh0h5odlxnZbsF2
+0Tzy3lEFHPUUBj6160itB95giHDKH1meW91L1ah8Z+nWES9GGBIAS/1XpeXtiE7/
+IuVmEuE8veAbwdMC9qRSEeq2zUWhA4m/KzTuli/GNErkXlazj3hlBs5WJ207ztTp
+HRGrAEjQgRKb3Ap2leowiE/u9D1Ean53g4v4gzDV1gx5uTZ395WfuWteO9ZUc9bo
+XMeGJiPcvyr2i8Do25ZWw+wW1T2TbcEAtyfOmgkCAwEAAaMTMBEwDwYDVR0TAQH/
+BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAPY6VDC0kfY+kGrM5YiNEjs6PjNjj
+ojWU5/UMjwfRqF8JtkNnV9LnBiNlNGUIV8b5OCyXKGjDlc+ISNRvpgGbZ4dzVIwE
+OKKL9tUB4IFwRAxO0UbLtVkwFeX3clzTezLkei7ahgUe04c2ZjFeO/mf/nuQWvWY
+hprLz5uiGtKWPcirec4wPLkuyHzQMv7Dx/5VYARuxhHkkplteVQ4k9nTxag372Re
+eHgH4KKgLTXEBjV55RoAtOsug+k+KT8U9FzU2ul/j+89tJihllkD1udqIkic8RMx
+qn/mBaIe/ENb88TzrSXcp2xE9rth+QtjpNAVGnE4hP87QukVgedq7JKV7Q==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIC1DCCAbygAwIBAgIDDYaqMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNVBAMTEWJs
+YWNrbGlzdCB0ZXN0IENBMCoYEzIwMTUwMTAxMDAwMDAwKzAwMDAYEzIwMjUwMTAx
+MDAwMDAwKzAwMDAwHDEaMBgGA1UEAxMRYmxhY2tsaXN0IHRlc3QgQ0EwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDafYp6+Gs5ZjfLfU2EH/NYpvdBUyPz
+veQBJCE4PhBYhOm+Z+J6aX0rSHqU4VTJ8H0TOb6Fh54zBUkIQJHx8YTIsXVmDj0O
+louWAa3uYpIOeBz46knJxdTI9NG6XnsHMYUICZPM8CHtHhoaYnhaRFTcGIg+Y9Hl
+BxMTYXXtqjicg10YuSuEkwMuDT7CbmnmYon8Gt5+ygHIe8YFWdCicpzm5wlPvRu4
+D+WiH2mTgfFG5D5QDoRnxnHWAcO8/+UenFtnbfRip9h6TrzXoJSHtuYW3rMCDVG3
+owVwUE3+ExMcbWKn+qaqGQsjrLlwyYEcKjhH67iPFcTtvZfCsgv8YG75AgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAILNS2XgO4Qa
+plyF7wbQFvVlFFe1QIiEiPZcopqb0zEse73IPBGUnoIt3C9keCv8Q6d7h0x2fe2N
+IqD4P9WXGQYiobBnTci1d2nW5dBq1WVDcpK4cNVsDX7SBE6sd19JEAazNSPIQJ6T
+sts2JXXdTssAyVqGAnq6TwQ2U5ArzuC5pCmr7FcfYAH0sCZM5VWw+ffJylDMBfeG
+oWyjH6f+TmkDd7yvIDh+ptn7Qv+LRxIjHDLPOxG9Y6JaDYtVqKJWh7er5/HFlwUi
+E6gpIuFM6It5ogUtmik2B19bPWpcnGFhv01IKBgmihpzd8LyCmxTtkK11KMxS1JF
+xZSCP3mJTbQ=
+-----END CERTIFICATE-----
diff --git a/src/test/resources/blacklist_test_valid_ca.pem b/src/test/resources/blacklist_test_valid_ca.pem
new file mode 100644
index 0000000..19148c7
--- /dev/null
+++ b/src/test/resources/blacklist_test_valid_ca.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICwDCCAaigAwIBAgIDBWa1MA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNVBAMTB1Rl
+c3QgQ2EwKhgTMjAxNTAxMDEwMDAwMDArMDAwMBgTMjAyNTAxMDEwMDAwMDArMDAw
+MDASMRAwDgYDVQQDEwdUZXN0IENhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAuk5Hq/uHOz7E3gEZFXKb0ZFslODflO7vB/VT3dmHyGXxuDK5fgQB4xPz
+uoU1VSpD9Pxpe9u+6jNlShEZ5xN34c2F6g+stU4lUS5udqCZVEtB6/etOOpMuiWU
+Ud2DVkEAn9weWkJmKy2gkLQ8p2Iw+0mPlhKKFI9brhGTEpQDTvW9sbLmSQFSEk30
+Ia5rxii/cgu8j5AQmsvUQA06vHXq6/xIsQIj1UFMycBmPz8BvrVO/c891vD9f2Uq
+gQg4p084rmsc6a7PAhBibTOFs3m91HNyZuY2M3pA1r1oLPRQ3WYXb8Wt+kHVtKAr
+L6qDXtofCU3RGhAruwjmuOWftgNsGwIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/
+MA0GCSqGSIb3DQEBCwUAA4IBAQCkFKi9HmsOyn4Wh6RpzwSh39L6e48IdOMcNpOK
+O38tO2rO/uNnhGn2ptnUJkwYS7XOy/A09q1iZNbiuwBweIxc8Z17vpNmk7cF4TMw
+lMRJjDE3Dm2qjTs/lDOknGuzB38Q8tGN/ZbYUHjjf4TZHk5FXCzRUUp+UMzxlOuc
+HAuNuBlQUW88s26h7NdNr115VCbouAI7YkWJRmS2FbeQD5Nwx/kZcvLtJyKasx+n
+imeqy3kCW1NzP9nwlsx2vwW6ydGsdHxqsfrRpdRSLHjzQDA+5m5xMNV0oTr86Iex
+mkqHtIMbOOUpzrE3PACA4m7IgA6AcSkV5gGM9AgqcYccC3St
+-----END CERTIFICATE-----
diff --git a/src/test/resources/blacklist_test_valid_chain.pem b/src/test/resources/blacklist_test_valid_chain.pem
new file mode 100644
index 0000000..e763a05
--- /dev/null
+++ b/src/test/resources/blacklist_test_valid_chain.pem
@@ -0,0 +1,87 @@
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaqgAwIBAgIDD37fMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNVBAMTDGlu
+dGVybWVkaWF0ZTAqGBMyMDE1MDEwMTAwMDAwMCswMDAwGBMyMDI1MDEwMTAwMDAw
+MCswMDAwMA8xDTALBgNVBAMTBGxlYWYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDNq1OWpxGZfNFw8E8ZPvYEXeaXEa1twBSKDe1EUctuck+F8Ethb0O1
+ooWA9egJh8GWSbxFdPfoJ/yyuor3sH5kkUtq94NO/1IXPn4xnrwrfvkeVR8e3pXn
+kAQm7MH8c8iPmQ59arfBjFfX9ZZhPiLDPq1bsQa8WqaajyylVVDzQcYseDSHoR/7
+3QmcfUZjH5qxYf7jcS8QdtfnD6faZuczM30qL7N3BLn2gcA5I5jVkrxQBKfLBPfl
+6k3aO6ekxSSxhSHqBv7x5VIzoiq666DGdelLuwrmMksx7Ni7cnXws3rlBYCr6wly
+Hux62YJ9Og3rC5lb3pjkmSzj31VVfFnpAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMB
+Af8wDQYJKoZIhvcNAQELBQADggEBAISuXogfdMHZiAs3CJwsOTjCLW0MGsqWH88j
+wdkbotZuTAb84Iq2vpoX/w95WlyakseFGHnAaexy4nzSNyn8LC5b4JMNQopn8Gxs
+y3p0Z+XC/PNC/4lVxQB8KARFvhtW7Ltw1jjIqbTq2ZTWVSCuqb+1ZnMihP4MYinb
+Ml/Q9N/pitaLolQ/pewm4YjqUA8rGC3OkyL06huz+Ow382TvMDVLk0nctMvCrg1h
+IJFlCD5I8xhcIAqp7wzEHVHQ9jRT9NjElG+PF6FwGi6IW3A8wL8fGru2N84OeJbs
+ROrn33HqVsoqZUdXSPG5YGxM7c7wfUBx3g1/Ou3gxLlqp4a/kX0=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICzzCCAbegAwIBAgIDDeS0MA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNVBAMTEWJs
+YWNrbGlzdCB0ZXN0IENBMCoYEzIwMTUwMTAxMDAwMDAwKzAwMDAYEzIwMjUwMTAx
+MDAwMDAwKzAwMDAwFzEVMBMGA1UEAxMMaW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2v+yrEqrNHOD30WnfdjgDQx+bWF46/zUArFU
+aeHSzjKEaZcSXI4a3vtFS5NH7AGE8kcrOWRSpgG9WC1CSSW9doHqz0eVK/vBDa62
+J3eZPh0kc2pgrwPRWZjzoQLpaApIq1j7xskp5PC21GA3mDKQCI/Z/TpuBoD38jwR
+TzmJOA4/+0zf+5dH4qyzHtE+K/WrUdNnonZ9ohK9WAlDhKAZ8N4VFb75VQJOYhdK
+sBiqQqBiw1Wg9IRSCeDSq3O6zjDznzQAa0hmKanqq+VVwgq8z9GRCXa3y2RawnU6
+oVfRKTQnRqUxtRobjXUCArDatsZ4xr1A4fDMCPcLyaEMOCG7CQIDAQABoxMwETAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQClkXYt95OajuH5Xqut
+KO52XMAeJSC+lAp7sT32tUAZgsV0x5YEAKbo6W9hWuSPdx99r9bPgfQ0sqc1gRgS
+wyW3ZbB/rNrQqQqNYzBWwKrg3uTCGA1o85SqX8aiDJuygBySllTzGztENTApWYwN
+LJATS9yPgn/31BHyfZ29v+6fa3cnuRitVGIW/thDwz8IPqPSNqGTO8Obf/6WDOK/
+7pkji2rHG25Gi/3mWOvnjejbKwb4w4ZlihcNc60ra+0qEM5xstGz6dMJ3sd/w/Fq
+7d/4qhAEpJ7GPg/A5eVGyTYhpYuBA68KoQrrPf2CCGUFQxLQm6UQlICB5AREWOmi
+hZGG
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICxTCCAa2gAwIBAgIDAIddMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNVBAMTB1Rl
+c3QgQ2EwKhgTMjAxNTAxMDEwMDAwMDArMDAwMBgTMjAyNTAxMDEwMDAwMDArMDAw
+MDAXMRUwEwYDVQQDEwxpbnRlcm1lZGlhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDa/7KsSqs0c4PfRad92OANDH5tYXjr/NQCsVRp4dLOMoRplxJc
+jhre+0VLk0fsAYTyRys5ZFKmAb1YLUJJJb12gerPR5Ur+8ENrrYnd5k+HSRzamCv
+A9FZmPOhAuloCkirWPvGySnk8LbUYDeYMpAIj9n9Om4GgPfyPBFPOYk4Dj/7TN/7
+l0firLMe0T4r9atR02eidn2iEr1YCUOEoBnw3hUVvvlVAk5iF0qwGKpCoGLDVaD0
+hFIJ4NKrc7rOMPOfNABrSGYpqeqr5VXCCrzP0ZEJdrfLZFrCdTqhV9EpNCdGpTG1
+GhuNdQICsNq2xnjGvUDh8MwI9wvJoQw4IbsJAgMBAAGjEzARMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJnqAkMbjA4+FFLAapxM+MMLjIVmtSB7
+je7U8APLI0jeY/Wye/OAsOI2vmn7PYVsCTQXr14sCJz863UHrrlDF8ejf0nqSfUM
+bSXvc23XuDmcDqoM2UroHqRmZa0SC1cFC6aJ5ODwioB98cSiPzr24aWcr43dtO4P
+OOjmDXzpC7E67amn3luUIpDJ8epHPIT8+hxP2FP7CHlYUxKQFh3l/t3ftlVF9QId
+992TbF9dDluhzWVh7jsNRJrq2cEIPn6dBsPRPncOcvYton4nvpmDaeS9/d5ktkij
+LCpJv0ECxC/kcPQu65twBWhPwER/hOV0Tq9VYVDpgP3k/K4YdXs1UhY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIC1DCCAbygAwIBAgIDDYaqMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNVBAMTEWJs
+YWNrbGlzdCB0ZXN0IENBMCoYEzIwMTUwMTAxMDAwMDAwKzAwMDAYEzIwMjUwMTAx
+MDAwMDAwKzAwMDAwHDEaMBgGA1UEAxMRYmxhY2tsaXN0IHRlc3QgQ0EwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDafYp6+Gs5ZjfLfU2EH/NYpvdBUyPz
+veQBJCE4PhBYhOm+Z+J6aX0rSHqU4VTJ8H0TOb6Fh54zBUkIQJHx8YTIsXVmDj0O
+louWAa3uYpIOeBz46knJxdTI9NG6XnsHMYUICZPM8CHtHhoaYnhaRFTcGIg+Y9Hl
+BxMTYXXtqjicg10YuSuEkwMuDT7CbmnmYon8Gt5+ygHIe8YFWdCicpzm5wlPvRu4
+D+WiH2mTgfFG5D5QDoRnxnHWAcO8/+UenFtnbfRip9h6TrzXoJSHtuYW3rMCDVG3
+owVwUE3+ExMcbWKn+qaqGQsjrLlwyYEcKjhH67iPFcTtvZfCsgv8YG75AgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAILNS2XgO4Qa
+plyF7wbQFvVlFFe1QIiEiPZcopqb0zEse73IPBGUnoIt3C9keCv8Q6d7h0x2fe2N
+IqD4P9WXGQYiobBnTci1d2nW5dBq1WVDcpK4cNVsDX7SBE6sd19JEAazNSPIQJ6T
+sts2JXXdTssAyVqGAnq6TwQ2U5ArzuC5pCmr7FcfYAH0sCZM5VWw+ffJylDMBfeG
+oWyjH6f+TmkDd7yvIDh+ptn7Qv+LRxIjHDLPOxG9Y6JaDYtVqKJWh7er5/HFlwUi
+E6gpIuFM6It5ogUtmik2B19bPWpcnGFhv01IKBgmihpzd8LyCmxTtkK11KMxS1JF
+xZSCP3mJTbQ=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICwDCCAaigAwIBAgIDBWa1MA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNVBAMTB1Rl
+c3QgQ2EwKhgTMjAxNTAxMDEwMDAwMDArMDAwMBgTMjAyNTAxMDEwMDAwMDArMDAw
+MDASMRAwDgYDVQQDEwdUZXN0IENhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAuk5Hq/uHOz7E3gEZFXKb0ZFslODflO7vB/VT3dmHyGXxuDK5fgQB4xPz
+uoU1VSpD9Pxpe9u+6jNlShEZ5xN34c2F6g+stU4lUS5udqCZVEtB6/etOOpMuiWU
+Ud2DVkEAn9weWkJmKy2gkLQ8p2Iw+0mPlhKKFI9brhGTEpQDTvW9sbLmSQFSEk30
+Ia5rxii/cgu8j5AQmsvUQA06vHXq6/xIsQIj1UFMycBmPz8BvrVO/c891vD9f2Uq
+gQg4p084rmsc6a7PAhBibTOFs3m91HNyZuY2M3pA1r1oLPRQ3WYXb8Wt+kHVtKAr
+L6qDXtofCU3RGhAruwjmuOWftgNsGwIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/
+MA0GCSqGSIb3DQEBCwUAA4IBAQCkFKi9HmsOyn4Wh6RpzwSh39L6e48IdOMcNpOK
+O38tO2rO/uNnhGn2ptnUJkwYS7XOy/A09q1iZNbiuwBweIxc8Z17vpNmk7cF4TMw
+lMRJjDE3Dm2qjTs/lDOknGuzB38Q8tGN/ZbYUHjjf4TZHk5FXCzRUUp+UMzxlOuc
+HAuNuBlQUW88s26h7NdNr115VCbouAI7YkWJRmS2FbeQD5Nwx/kZcvLtJyKasx+n
+imeqy3kCW1NzP9nwlsx2vwW6ydGsdHxqsfrRpdRSLHjzQDA+5m5xMNV0oTr86Iex
+mkqHtIMbOOUpzrE3PACA4m7IgA6AcSkV5gGM9AgqcYccC3St
+-----END CERTIFICATE-----
diff --git a/src/test/resources/test_blacklist_ca.pem b/src/test/resources/test_blacklist_ca.pem
new file mode 100644
index 0000000..b087d56
--- /dev/null
+++ b/src/test/resources/test_blacklist_ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC1DCCAbygAwIBAgIDDYaqMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNVBAMTEWJs
+YWNrbGlzdCB0ZXN0IENBMCoYEzIwMTUwMTAxMDAwMDAwKzAwMDAYEzIwMjUwMTAx
+MDAwMDAwKzAwMDAwHDEaMBgGA1UEAxMRYmxhY2tsaXN0IHRlc3QgQ0EwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDafYp6+Gs5ZjfLfU2EH/NYpvdBUyPz
+veQBJCE4PhBYhOm+Z+J6aX0rSHqU4VTJ8H0TOb6Fh54zBUkIQJHx8YTIsXVmDj0O
+louWAa3uYpIOeBz46knJxdTI9NG6XnsHMYUICZPM8CHtHhoaYnhaRFTcGIg+Y9Hl
+BxMTYXXtqjicg10YuSuEkwMuDT7CbmnmYon8Gt5+ygHIe8YFWdCicpzm5wlPvRu4
+D+WiH2mTgfFG5D5QDoRnxnHWAcO8/+UenFtnbfRip9h6TrzXoJSHtuYW3rMCDVG3
+owVwUE3+ExMcbWKn+qaqGQsjrLlwyYEcKjhH67iPFcTtvZfCsgv8YG75AgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAILNS2XgO4Qa
+plyF7wbQFvVlFFe1QIiEiPZcopqb0zEse73IPBGUnoIt3C9keCv8Q6d7h0x2fe2N
+IqD4P9WXGQYiobBnTci1d2nW5dBq1WVDcpK4cNVsDX7SBE6sd19JEAazNSPIQJ6T
+sts2JXXdTssAyVqGAnq6TwQ2U5ArzuC5pCmr7FcfYAH0sCZM5VWw+ffJylDMBfeG
+oWyjH6f+TmkDd7yvIDh+ptn7Qv+LRxIjHDLPOxG9Y6JaDYtVqKJWh7er5/HFlwUi
+E6gpIuFM6It5ogUtmik2B19bPWpcnGFhv01IKBgmihpzd8LyCmxTtkK11KMxS1JF
+xZSCP3mJTbQ=
+-----END CERTIFICATE-----
diff --git a/src/test/resources/test_blacklist_ca_key.pem b/src/test/resources/test_blacklist_ca_key.pem
new file mode 100644
index 0000000..dd30c91
--- /dev/null
+++ b/src/test/resources/test_blacklist_ca_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDafYp6+Gs5ZjfL
+fU2EH/NYpvdBUyPzveQBJCE4PhBYhOm+Z+J6aX0rSHqU4VTJ8H0TOb6Fh54zBUkI
+QJHx8YTIsXVmDj0OlouWAa3uYpIOeBz46knJxdTI9NG6XnsHMYUICZPM8CHtHhoa
+YnhaRFTcGIg+Y9HlBxMTYXXtqjicg10YuSuEkwMuDT7CbmnmYon8Gt5+ygHIe8YF
+WdCicpzm5wlPvRu4D+WiH2mTgfFG5D5QDoRnxnHWAcO8/+UenFtnbfRip9h6TrzX
+oJSHtuYW3rMCDVG3owVwUE3+ExMcbWKn+qaqGQsjrLlwyYEcKjhH67iPFcTtvZfC
+sgv8YG75AgMBAAECggEAd1vBvO/c05yNunKXWCiELdf4lw0uRMdluWHda/Yrw8/I
+SaZCyRC7ult76701LqRcD5aqCBRQThsDDKkJkZyZJ3Iaakg4/rErTCVauTHMDG99
+lFWZPcr/NVDZCfD3ULSysfNZdMlyHzEknWlRyi4uFZapRzwMvAsjVqEVZWJqTsVK
+AybEY37ktPyu1TMerUGUXKkibGaexeJ1xhl4oquL0AIHfjkA+NdJM2WSMm6/pZSN
+rHq8qV3DCgbPk2yHUuHAxvw9aa/bKHPOoazmfZZ3aAyr+3HxQgHHpPfOk2nWszin
+0jWSaHbarSe/ULmmx/LJcLxm28hla2o06VPgpwtiyQKBgQD2rcpKm/ZvcaTCbyBf
+nIcqRDSQgK132IlXre21DMe9F6ieiC3Yzuj5Fp0macviw5raHyBmjIEPIrbd0yOh
+czR2ioZbRMdf7b1dns0lPx4YAn3kwZZ72s39PlNw13as2yDoVC55OGouYAGiBvO2
+y3hNDrR3iK3ZXGoCYrutQm73jwKBgQDivxLriEWRsRm7ZKNJ4b6la0seOyPhjh7E
+JIuQfkjETD+42KGderRcAEjGloUPsoy1/8LDM9j/Dakvxp9PA61tY1qwUDFLHO2l
+1EBOXAZisMzy3HkXBI11Z9zylEC3OBRL6jCfWa1aRM1eBxv33cpgsb6oWPhhCVPs
+pGLtmY0s9wKBgFJPcyyqFfThysRGKFs+86sazx9YkIlo64siMiszdIKYHl+nuQSb
+JgnXjeB/dNTZyBX4ROty/q16O+KQzVbWBi930ZUqwgw0W/edQX6oLPZ9/lwSbJAv
+VoSmA1mny6WqCLT9QfSY6nVG+8SA5VmdUysDORyZssjQmV7qaw1JGZXpAoGAd6v6
+816XwR4kg5fI6qx/b1Tib5EtDdVxfXoAQwGzrA7GLuv+2Fuzpz7rKgy1K6TDySa0
+h0vtAigWnEWLPSums64VZirc6VTaRIRycCj3oczIToF4U2KuukFYBpuiUFEDvVFb
+2i59ZMAdV7wO0dI4BrKo+rcCWEyRA7t7DwXU0d8CgYEArLHjZ8gJydZlmH/pV0iY
+Vsr+yKOStS5V4DRl/0tr/K29hjaDXlptiOcVV7tLDhW2jywFUFZgfd5/KHiiRk8H
+BPL7XK+6cjgTTjdChWy2GOoGu9nr41D9O9LxXPc3EvhpGMzLFK+Qh4Wu1Yirtbje
+9KByDtJ8ext4Z+JgJYYP5zg=
+-----END PRIVATE KEY-----