1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.org.bouncycastle.jce.provider;
18
19import java.io.ByteArrayInputStream;
20import java.io.File;
21import java.io.FileOutputStream;
22import java.io.FileNotFoundException;
23import java.io.InputStream;
24import java.io.IOException;
25import java.math.BigInteger;
26import java.security.cert.CertificateFactory;
27import java.security.cert.Certificate;
28import java.security.MessageDigest;
29import java.security.PrivateKey;
30import java.security.PublicKey;
31import java.util.HashSet;
32import java.util.Set;
33import junit.framework.TestCase;
34import com.android.org.bouncycastle.jce.provider.CertBlacklist;
35import com.android.org.bouncycastle.crypto.Digest;
36import com.android.org.bouncycastle.util.encoders.Base64;
37import com.android.org.bouncycastle.util.encoders.Hex;
38
39public class CertBlacklistTest extends TestCase {
40
41    private File tmpFile;
42
43    private Set<String> DEFAULT_PUBKEYS;
44    private Set<String> DEFAULT_SERIALS;
45
46    public static final String TEST_CERT = "" +
47                    "MIIDsjCCAxugAwIBAgIJAPLf2gS0zYGUMA0GCSqGSIb3DQEBBQUAMIGYMQswCQYDVQQGEwJVUzET" +
48                    "MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEPMA0GA1UEChMGR29v" +
49                    "Z2xlMRAwDgYDVQQLEwd0ZXN0aW5nMRYwFAYDVQQDEw1HZXJlbXkgQ29uZHJhMSEwHwYJKoZIhvcN" +
50                    "AQkBFhJnY29uZHJhQGdvb2dsZS5jb20wHhcNMTIwNzE0MTc1MjIxWhcNMTIwODEzMTc1MjIxWjCB" +
51                    "mDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZp" +
52                    "ZXcxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHdGVzdGluZzEWMBQGA1UEAxMNR2VyZW15IENv" +
53                    "bmRyYTEhMB8GCSqGSIb3DQEJARYSZ2NvbmRyYUBnb29nbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUA" +
54                    "A4GNADCBiQKBgQCjGGHATBYlmas+0sEECkno8LZ1KPglb/mfe6VpCT3GhSr+7br7NG/ZwGZnEhLq" +
55                    "E7YIH4fxltHmQC3Tz+jM1YN+kMaQgRRjo/LBCJdOKaMwUbkVynAH6OYsKevjrOPk8lfM5SFQzJMG" +
56                    "sA9+Tfopr5xg0BwZ1vA/+E3mE7Tr3M2UvwIDAQABo4IBADCB/TAdBgNVHQ4EFgQUhzkS9E6G+x8W" +
57                    "L4EsmRjDxu28tHUwgc0GA1UdIwSBxTCBwoAUhzkS9E6G+x8WL4EsmRjDxu28tHWhgZ6kgZswgZgx" +
58                    "CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3" +
59                    "MQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB3Rlc3RpbmcxFjAUBgNVBAMTDUdlcmVteSBDb25k" +
60                    "cmExITAfBgkqhkiG9w0BCQEWEmdjb25kcmFAZ29vZ2xlLmNvbYIJAPLf2gS0zYGUMAwGA1UdEwQF" +
61                    "MAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAYiugFDmbDOQ2U/+mqNt7o8ftlEo9SJrns6O8uTtK6AvR" +
62                    "orDrR1AXTXkuxwLSbmVfedMGOZy7Awh7iZa8hw5x9XmUudfNxvmrKVEwGQY2DZ9PXbrnta/dwbhK" +
63                    "mWfoepESVbo7CKIhJp8gRW0h1Z55ETXD57aGJRvQS4pxkP8ANhM=";
64
65    public CertBlacklistTest() throws IOException {
66        tmpFile = File.createTempFile("test", "");
67        DEFAULT_PUBKEYS = getDefaultPubkeys();
68        DEFAULT_SERIALS = getDefaultSerials();
69        tmpFile.delete();
70    }
71
72    @Override
73    public void setUp() throws Exception {
74        super.setUp();
75        tmpFile = File.createTempFile("test", "");
76    }
77
78    @Override
79    public void tearDown() throws Exception {
80        try {
81            tmpFile.delete();
82        } finally {
83            super.tearDown();
84        }
85    }
86
87    private Set<String> getPubkeyBlacklist(String path) throws IOException {
88        // set our blacklist path
89        CertBlacklist bl = new CertBlacklist(path, CertBlacklist.DEFAULT_SERIAL_BLACKLIST_PATH);
90        // call readPubkeyBlacklist
91        Set<byte[]> arr = bl.pubkeyBlacklist;
92        // convert the results to a hashset of strings
93        Set<String> results = new HashSet<String>();
94        for (byte[] value: arr) {
95            results.add(new String(value));
96        }
97        return results;
98    }
99
100    private Set<String> getSerialBlacklist(String path) throws IOException {
101        // set our blacklist path
102        CertBlacklist bl = new CertBlacklist(CertBlacklist.DEFAULT_PUBKEY_BLACKLIST_PATH, path);
103        // call readPubkeyBlacklist
104        Set<BigInteger> arr = bl.serialBlacklist;
105        // convert the results to a hashset of strings
106        Set<String> results = new HashSet<String>();
107        for (BigInteger value: arr) {
108            results.add(value.toString(16));
109        }
110        return results;
111    }
112
113    private String getHash(PublicKey publicKey) throws Exception {
114        byte[] encoded = publicKey.getEncoded();
115        MessageDigest digest = MessageDigest.getInstance("SHA1");
116        byte[] hexlifiedHash = Hex.encode(digest.digest(encoded));
117        return new String(hexlifiedHash);
118    }
119
120    private Set<String> getDefaultPubkeys() throws IOException {
121        return getPubkeyBlacklist("");
122    }
123
124    private Set<String> getDefaultSerials() throws IOException {
125        return getSerialBlacklist("");
126    }
127
128    private Set<String> getCurrentPubkeyBlacklist() throws IOException {
129        return getPubkeyBlacklist(tmpFile.getCanonicalPath());
130    }
131
132    private Set<String> getCurrentSerialBlacklist() throws IOException {
133        return getSerialBlacklist(tmpFile.getCanonicalPath());
134    }
135
136    private void blacklistToFile(String blacklist) throws IOException {
137        FileOutputStream out = new FileOutputStream(tmpFile);
138        out.write(blacklist.toString().getBytes());
139        out.close();
140    }
141
142    private void writeBlacklist(HashSet<String> values) throws IOException {
143        StringBuilder result = new StringBuilder();
144        // join the values into a string
145        for (String value : values) {
146            if (result.length() != 0) {
147                result.append(",");
148            }
149            result.append(value);
150        }
151        blacklistToFile(result.toString());
152    }
153
154    private PublicKey createPublicKey(String cert) throws Exception {
155        byte[] derCert = Base64.decode(cert.getBytes());
156        InputStream istream = new ByteArrayInputStream(derCert);
157        CertificateFactory cf = CertificateFactory.getInstance("X.509");
158        return cf.generateCertificate(istream).getPublicKey();
159    }
160
161    public void testPubkeyBlacklistLegit() throws Exception {
162        // build the blacklist
163        HashSet<String> bl = new HashSet<String>();
164        bl.add("6ccabd7db47e94a5759901b6a7dfd45d1c091ccc");
165        // write the blacklist
166        writeBlacklist(bl);
167        // add the default pubkeys into the bl
168        bl.addAll(DEFAULT_PUBKEYS);
169        // do the test
170        assertEquals(bl, getCurrentPubkeyBlacklist());
171    }
172
173    public void testLegitPubkeyIsntBlacklisted() throws Exception {
174        // build the public key
175        PublicKey pk = createPublicKey(TEST_CERT);
176        // write that to the test blacklist
177        writeBlacklist(new HashSet<String>());
178        // set our blacklist path
179        CertBlacklist bl = new CertBlacklist(tmpFile.getCanonicalPath(),
180                                             CertBlacklist.DEFAULT_SERIAL_BLACKLIST_PATH);
181        // check to make sure it isn't blacklisted
182        assertEquals(bl.isPublicKeyBlackListed(pk), false);
183    }
184
185    public void testPubkeyIsBlacklisted() throws Exception {
186        // build the public key
187        PublicKey pk = createPublicKey(TEST_CERT);
188        // get its hash
189        String hash = getHash(pk);
190        // write that to the test blacklist
191        HashSet<String> testBlackList = new HashSet<String>();
192        testBlackList.add(hash);
193        writeBlacklist(testBlackList);
194        // set our blacklist path
195        CertBlacklist bl = new CertBlacklist(tmpFile.getCanonicalPath(),
196                                             CertBlacklist.DEFAULT_SERIAL_BLACKLIST_PATH);
197        // check to make sure it isn't blacklited
198        assertTrue(bl.isPublicKeyBlackListed(pk));
199    }
200
201    public void testSerialBlacklistLegit() throws IOException {
202        // build the blacklist
203        HashSet<String> bl = new HashSet<String>();
204        bl.add("22e514121e61c643b1e9b06bd4b9f7d0");
205        // write the blacklist
206        writeBlacklist(bl);
207        // add the default serials into the bl
208        bl.addAll(DEFAULT_SERIALS);
209        // do the test
210        assertEquals(bl, getCurrentSerialBlacklist());
211    }
212
213    public void testPubkeyBlacklistMultipleLegit() throws IOException {
214        // build the blacklist
215        HashSet<String> bl = new HashSet<String>();
216        bl.add("6ccabd7db47e94a5759901b6a7dfd45d1c091ccc");
217        bl.add("6ccabd7db47e94a5759901b6a7dfd45d1c091ccd");
218        // write the blacklist
219        writeBlacklist(bl);
220        // add the default pubkeys into the bl
221        bl.addAll(DEFAULT_PUBKEYS);
222        // do the test
223        assertEquals(bl, getCurrentPubkeyBlacklist());
224    }
225
226    public void testSerialBlacklistMultipleLegit() throws IOException {
227        // build the blacklist
228        HashSet<String> bl = new HashSet<String>();
229        bl.add("22e514121e61c643b1e9b06bd4b9f7d0");
230        bl.add("22e514121e61c643b1e9b06bd4b9f7d1");
231        // write the blacklist
232        writeBlacklist(bl);
233        // add the default serials into the bl
234        bl.addAll(DEFAULT_SERIALS);
235        // do the test
236        assertEquals(bl, getCurrentSerialBlacklist());
237    }
238
239    public void testPubkeyBlacklistMultipleBad() throws IOException {
240        // build the blacklist
241        HashSet<String> bl = new HashSet<String>();
242        bl.add("6ccabd7db47e94a5759901b6a7dfd45d1c091ccc");
243        bl.add("");
244        bl.add("6ccabd7db47e94a5759901b6a7dfd45d1c091ccd");
245        // write the blacklist
246        writeBlacklist(bl);
247        // add the default pubkeys into the bl
248        bl.addAll(DEFAULT_PUBKEYS);
249        // remove the bad one
250        bl.remove("");
251        // do the test- results should be all but the bad one are handled
252        assertEquals(bl, getCurrentPubkeyBlacklist());
253    }
254
255    public void testSerialBlacklistMultipleBad() throws IOException {
256        // build the blacklist
257        HashSet<String> bl = new HashSet<String>();
258        bl.add("22e514121e61c643b1e9b06bd4b9f7d0");
259        bl.add("");
260        bl.add("22e514121e61c643b1e9b06bd4b9f7d1");
261        // write the blacklist
262        writeBlacklist(bl);
263        // add the default serials into the bl
264        bl.addAll(DEFAULT_SERIALS);
265        // remove the bad one
266        bl.remove("");
267        // do the test- results should be all but the bad one are handled
268        assertEquals(bl, getCurrentSerialBlacklist());
269    }
270
271    public void testPubkeyBlacklistDoesntExist() throws IOException {
272        assertEquals(DEFAULT_PUBKEYS, getCurrentPubkeyBlacklist());
273    }
274
275    public void testSerialBlacklistDoesntExist() throws IOException {
276        assertEquals(DEFAULT_SERIALS, getCurrentSerialBlacklist());
277    }
278
279    public void testPubkeyBlacklistNotHexValues() throws IOException {
280        // build the blacklist
281        HashSet<String> bl = new HashSet<String>();
282        bl.add("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ");
283        // write the blacklist
284        writeBlacklist(bl);
285        // do the test
286        assertEquals(DEFAULT_PUBKEYS, getCurrentPubkeyBlacklist());
287    }
288
289    public void testSerialBlacklistNotHexValues() throws IOException {
290        // build the blacklist
291        HashSet<String> bl = new HashSet<String>();
292        bl.add("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ");
293        // write the blacklist
294        writeBlacklist(bl);
295        // do the test
296        assertEquals(DEFAULT_SERIALS, getCurrentSerialBlacklist());
297    }
298
299    public void testPubkeyBlacklistIncorrectLength() throws IOException {
300        // build the blacklist
301        HashSet<String> bl = new HashSet<String>();
302        bl.add("6ccabd7db47e94a5759901b6a7dfd45d1c091cc");
303        // write the blacklist
304        writeBlacklist(bl);
305        // do the test
306        assertEquals(DEFAULT_PUBKEYS, getCurrentPubkeyBlacklist());
307    }
308
309    public void testSerialBlacklistZero() throws IOException {
310        // build the blacklist
311        HashSet<String> bl = new HashSet<String>();
312        bl.add("0");
313        // write the blacklist
314        writeBlacklist(bl);
315        // add the default serials
316        bl.addAll(DEFAULT_SERIALS);
317        // do the test
318        assertEquals(bl, getCurrentSerialBlacklist());
319    }
320
321    public void testSerialBlacklistNegative() throws IOException {
322        // build the blacklist
323        HashSet<String> bl = new HashSet<String>();
324        bl.add("-1");
325        // write the blacklist
326        writeBlacklist(bl);
327        // add the default serials
328        bl.addAll(DEFAULT_SERIALS);
329        // do the test
330        assertEquals(bl, getCurrentSerialBlacklist());
331    }
332}
333