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