• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 
17 package org.conscrypt;
18 
19 import java.io.File;
20 import java.io.FileOutputStream;
21 import java.io.OutputStream;
22 import java.security.KeyStore;
23 import java.security.PrivateKey;
24 import java.security.PublicKey;
25 import java.security.cert.X509Certificate;
26 import java.util.Arrays;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Random;
30 import java.util.Set;
31 import javax.security.auth.x500.X500Principal;
32 import junit.framework.TestCase;
33 import libcore.java.security.TestKeyStore;
34 
35 public class TrustedCertificateStoreTest extends TestCase {
36     private static final Random tempFileRandom = new Random();
37 
38     private final File dirTest = new File(System.getProperty("java.io.tmpdir", "."),
39             "cert-store-test" + tempFileRandom.nextInt());
40     private final File dirSystem = new File(dirTest, "system");
41     private final File dirAdded = new File(dirTest, "added");
42     private final File dirDeleted = new File(dirTest, "removed");
43 
44     private static X509Certificate CA1;
45     private static X509Certificate CA2;
46 
47     private static KeyStore.PrivateKeyEntry PRIVATE;
48     private static X509Certificate[] CHAIN;
49 
50     private static X509Certificate CA3_WITH_CA1_SUBJECT;
51     private static String ALIAS_SYSTEM_CA1;
52     private static String ALIAS_SYSTEM_CA2;
53     private static String ALIAS_USER_CA1;
54     private static String ALIAS_USER_CA2;
55 
56     private static String ALIAS_SYSTEM_CHAIN0;
57     private static String ALIAS_SYSTEM_CHAIN1;
58     private static String ALIAS_SYSTEM_CHAIN2;
59     private static String ALIAS_USER_CHAIN0;
60     private static String ALIAS_USER_CHAIN1;
61     private static String ALIAS_USER_CHAIN2;
62 
63     private static String ALIAS_SYSTEM_CA3;
64     private static String ALIAS_SYSTEM_CA3_COLLISION;
65     private static String ALIAS_USER_CA3;
66     private static String ALIAS_USER_CA3_COLLISION;
67 
getCa1()68     private static X509Certificate getCa1() {
69         initCerts();
70         return CA1;
71     }
getCa2()72     private static X509Certificate getCa2() {
73         initCerts();
74         return CA2;
75     }
76 
getPrivate()77     private static KeyStore.PrivateKeyEntry getPrivate() {
78         initCerts();
79         return PRIVATE;
80     }
getChain()81     private static X509Certificate[] getChain() {
82         initCerts();
83         return CHAIN;
84     }
85 
getCa3WithCa1Subject()86     private static X509Certificate getCa3WithCa1Subject() {
87         initCerts();
88         return CA3_WITH_CA1_SUBJECT;
89     }
90 
getAliasSystemCa1()91     private static String getAliasSystemCa1() {
92         initCerts();
93         return ALIAS_SYSTEM_CA1;
94     }
getAliasSystemCa2()95     private static String getAliasSystemCa2() {
96         initCerts();
97         return ALIAS_SYSTEM_CA2;
98     }
getAliasUserCa1()99     private static String getAliasUserCa1() {
100         initCerts();
101         return ALIAS_USER_CA1;
102     }
getAliasUserCa2()103     private static String getAliasUserCa2() {
104         initCerts();
105         return ALIAS_USER_CA2;
106     }
107 
getAliasSystemChain0()108     private static String getAliasSystemChain0() {
109         initCerts();
110         return ALIAS_SYSTEM_CHAIN0;
111     }
getAliasSystemChain1()112     private static String getAliasSystemChain1() {
113         initCerts();
114         return ALIAS_SYSTEM_CHAIN1;
115     }
getAliasSystemChain2()116     private static String getAliasSystemChain2() {
117         initCerts();
118         return ALIAS_SYSTEM_CHAIN2;
119     }
getAliasUserChain0()120     private static String getAliasUserChain0() {
121         initCerts();
122         return ALIAS_USER_CHAIN0;
123     }
getAliasUserChain1()124     private static String getAliasUserChain1() {
125         initCerts();
126         return ALIAS_USER_CHAIN1;
127     }
getAliasUserChain2()128     private static String getAliasUserChain2() {
129         initCerts();
130         return ALIAS_USER_CHAIN2;
131     }
132 
getAliasSystemCa3()133     private static String getAliasSystemCa3() {
134         initCerts();
135         return ALIAS_SYSTEM_CA3;
136     }
getAliasSystemCa3Collision()137     private static String getAliasSystemCa3Collision() {
138         initCerts();
139         return ALIAS_SYSTEM_CA3_COLLISION;
140     }
getAliasUserCa3()141     private static String getAliasUserCa3() {
142         initCerts();
143         return ALIAS_USER_CA3;
144     }
getAliasUserCa3Collision()145     private static String getAliasUserCa3Collision() {
146         initCerts();
147         return ALIAS_USER_CA3_COLLISION;
148     }
149 
150     /**
151      * Lazily create shared test certificates.
152      */
initCerts()153     private static synchronized void initCerts() {
154         if (CA1 != null) {
155             return;
156         }
157         try {
158             CA1 = TestKeyStore.getClient().getRootCertificate("RSA");
159             CA2 = TestKeyStore.getClientCA2().getRootCertificate("RSA");
160             PRIVATE = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
161             CHAIN = (X509Certificate[]) PRIVATE.getCertificateChain();
162             CA3_WITH_CA1_SUBJECT = new TestKeyStore.Builder()
163                     .aliasPrefix("unused")
164                     .subject(CA1.getSubjectX500Principal())
165                     .ca(true)
166                     .build().getRootCertificate("RSA");
167 
168 
169             ALIAS_SYSTEM_CA1 = alias(false, CA1, 0);
170             ALIAS_SYSTEM_CA2 = alias(false, CA2, 0);
171             ALIAS_USER_CA1 = alias(true, CA1, 0);
172             ALIAS_USER_CA2 = alias(true, CA2, 0);
173 
174             ALIAS_SYSTEM_CHAIN0 = alias(false, getChain()[0], 0);
175             ALIAS_SYSTEM_CHAIN1 = alias(false, getChain()[1], 0);
176             ALIAS_SYSTEM_CHAIN2 = alias(false, getChain()[2], 0);
177             ALIAS_USER_CHAIN0 = alias(true, getChain()[0], 0);
178             ALIAS_USER_CHAIN1 = alias(true, getChain()[1], 0);
179             ALIAS_USER_CHAIN2 = alias(true, getChain()[2], 0);
180 
181             ALIAS_SYSTEM_CA3 = alias(false, CA3_WITH_CA1_SUBJECT, 0);
182             ALIAS_SYSTEM_CA3_COLLISION = alias(false, CA3_WITH_CA1_SUBJECT, 1);
183             ALIAS_USER_CA3 = alias(true, CA3_WITH_CA1_SUBJECT, 0);
184             ALIAS_USER_CA3_COLLISION = alias(true, CA3_WITH_CA1_SUBJECT, 1);
185         } catch (Exception e) {
186             throw new RuntimeException(e);
187         }
188     }
189 
190     private TrustedCertificateStore store;
191 
setUp()192     @Override protected void setUp() {
193         setupStore();
194     }
195 
setupStore()196     private void setupStore() {
197         dirSystem.mkdirs();
198         cleanStore();
199         createStore();
200     }
201 
createStore()202     private void createStore() {
203         store = new TrustedCertificateStore(dirSystem, dirAdded, dirDeleted);
204     }
205 
tearDown()206     @Override protected void tearDown() {
207         cleanStore();
208     }
209 
cleanStore()210     private void cleanStore() {
211         for (File dir : new File[] { dirSystem, dirAdded, dirDeleted, dirTest }) {
212             File[] files = dir.listFiles();
213             if (files == null) {
214                 continue;
215             }
216             for (File file : files) {
217                 assertTrue("Should delete " + file.getPath(), file.delete());
218             }
219         }
220         store = null;
221     }
222 
resetStore()223     private void resetStore() {
224         cleanStore();
225         setupStore();
226     }
227 
testEmptyDirectories()228     public void testEmptyDirectories() throws Exception {
229         assertEmpty();
230     }
231 
testOneSystemOneDeleted()232     public void testOneSystemOneDeleted() throws Exception {
233         install(getCa1(), getAliasSystemCa1());
234         store.deleteCertificateEntry(getAliasSystemCa1());
235         assertEmpty();
236         assertDeleted(getCa1(), getAliasSystemCa1());
237     }
238 
testTwoSystemTwoDeleted()239     public void testTwoSystemTwoDeleted() throws Exception {
240         install(getCa1(), getAliasSystemCa1());
241         store.deleteCertificateEntry(getAliasSystemCa1());
242         install(getCa2(), getAliasSystemCa2());
243         store.deleteCertificateEntry(getAliasSystemCa2());
244         assertEmpty();
245         assertDeleted(getCa1(), getAliasSystemCa1());
246         assertDeleted(getCa2(), getAliasSystemCa2());
247     }
248 
testPartialFileIsIgnored()249     public void testPartialFileIsIgnored() throws Exception {
250         File file = file(getAliasSystemCa1());
251         file.getParentFile().mkdirs();
252         OutputStream os = new FileOutputStream(file);
253         os.write(0);
254         os.close();
255         assertTrue(file.exists());
256         assertEmpty();
257         assertTrue(file.exists());
258     }
259 
assertEmpty()260     private void assertEmpty() throws Exception {
261         try {
262             store.getCertificate(null);
263             fail();
264         } catch (NullPointerException expected) {
265         }
266         assertNull(store.getCertificate(""));
267 
268         try {
269             store.getCreationDate(null);
270             fail();
271         } catch (NullPointerException expected) {
272         }
273         assertNull(store.getCreationDate(""));
274 
275         Set<String> s = store.aliases();
276         assertNotNull(s);
277         assertTrue(s.isEmpty());
278         assertAliases();
279 
280         Set<String> u = store.userAliases();
281         assertNotNull(u);
282         assertTrue(u.isEmpty());
283 
284         try {
285             store.containsAlias(null);
286             fail();
287         } catch (NullPointerException expected) {
288         }
289         assertFalse(store.containsAlias(""));
290 
291         assertNull(store.getCertificateAlias(null));
292         assertNull(store.getCertificateAlias(getCa1()));
293 
294         try {
295             store.getTrustAnchor(null);
296             fail();
297         } catch (NullPointerException expected) {
298         }
299         assertNull(store.getTrustAnchor(getCa1()));
300 
301         try {
302             store.findIssuer(null);
303             fail();
304         } catch (NullPointerException expected) {
305         }
306         assertNull(store.findIssuer(getCa1()));
307 
308         try {
309             store.installCertificate(null);
310             fail();
311         } catch (NullPointerException expected) {
312         }
313 
314         store.deleteCertificateEntry(null);
315         store.deleteCertificateEntry("");
316 
317         String[] userFiles = dirAdded.list();
318         assertTrue(userFiles == null || userFiles.length == 0);
319     }
320 
testTwoSystem()321     public void testTwoSystem() throws Exception {
322         testTwo(getCa1(), getAliasSystemCa1(),
323                 getCa2(), getAliasSystemCa2());
324     }
325 
testTwoUser()326     public void testTwoUser() throws Exception {
327         testTwo(getCa1(), getAliasUserCa1(),
328                 getCa2(), getAliasUserCa2());
329     }
330 
testOneSystemOneUser()331     public void testOneSystemOneUser() throws Exception {
332         testTwo(getCa1(), getAliasSystemCa1(),
333                 getCa2(), getAliasUserCa2());
334     }
335 
testTwoSystemSameSubject()336     public void testTwoSystemSameSubject() throws Exception {
337         testTwo(getCa1(), getAliasSystemCa1(),
338                 getCa3WithCa1Subject(), getAliasSystemCa3Collision());
339     }
340 
testTwoUserSameSubject()341     public void testTwoUserSameSubject() throws Exception {
342         testTwo(getCa1(), getAliasUserCa1(),
343                 getCa3WithCa1Subject(), getAliasUserCa3Collision());
344 
345         store.deleteCertificateEntry(getAliasUserCa1());
346         assertDeleted(getCa1(), getAliasUserCa1());
347         assertTombstone(getAliasUserCa1());
348         assertRootCa(getCa3WithCa1Subject(), getAliasUserCa3Collision());
349         assertAliases(getAliasUserCa3Collision());
350 
351         store.deleteCertificateEntry(getAliasUserCa3Collision());
352         assertDeleted(getCa3WithCa1Subject(), getAliasUserCa3Collision());
353         assertNoTombstone(getAliasUserCa3Collision());
354         assertNoTombstone(getAliasUserCa1());
355         assertEmpty();
356     }
357 
testOneSystemOneUserSameSubject()358     public void testOneSystemOneUserSameSubject() throws Exception {
359         testTwo(getCa1(), getAliasSystemCa1(),
360                 getCa3WithCa1Subject(), getAliasUserCa3());
361         testTwo(getCa1(), getAliasUserCa1(),
362                 getCa3WithCa1Subject(), getAliasSystemCa3());
363     }
364 
testTwo(X509Certificate x1, String alias1, X509Certificate x2, String alias2)365     private void testTwo(X509Certificate x1, String alias1,
366                          X509Certificate x2, String alias2) {
367         install(x1, alias1);
368         install(x2, alias2);
369         assertRootCa(x1, alias1);
370         assertRootCa(x2, alias2);
371         assertAliases(alias1, alias2);
372     }
373 
374 
testOneSystemOneUserOneDeleted()375     public void testOneSystemOneUserOneDeleted() throws Exception {
376         install(getCa1(), getAliasSystemCa1());
377         store.installCertificate(getCa2());
378         store.deleteCertificateEntry(getAliasSystemCa1());
379         assertDeleted(getCa1(), getAliasSystemCa1());
380         assertRootCa(getCa2(), getAliasUserCa2());
381         assertAliases(getAliasUserCa2());
382     }
383 
testOneSystemOneUserOneDeletedSameSubject()384     public void testOneSystemOneUserOneDeletedSameSubject() throws Exception {
385         install(getCa1(), getAliasSystemCa1());
386         store.installCertificate(getCa3WithCa1Subject());
387         store.deleteCertificateEntry(getAliasSystemCa1());
388         assertDeleted(getCa1(), getAliasSystemCa1());
389         assertRootCa(getCa3WithCa1Subject(), getAliasUserCa3());
390         assertAliases(getAliasUserCa3());
391     }
392 
testUserMaskingSystem()393     public void testUserMaskingSystem() throws Exception {
394         install(getCa1(), getAliasSystemCa1());
395         install(getCa1(), getAliasUserCa1());
396         assertMasked(getCa1(), getAliasSystemCa1());
397         assertRootCa(getCa1(), getAliasUserCa1());
398         assertAliases(getAliasSystemCa1(), getAliasUserCa1());
399     }
400 
testChain()401     public void testChain() throws Exception {
402         testChain(getAliasSystemChain1(), getAliasSystemChain2());
403         testChain(getAliasSystemChain1(), getAliasUserChain2());
404         testChain(getAliasUserChain1(), getAliasSystemCa1());
405         testChain(getAliasUserChain1(), getAliasUserChain2());
406     }
407 
testChain(String alias1, String alias2)408     private void testChain(String alias1, String alias2) throws Exception {
409         install(getChain()[1], alias1);
410         install(getChain()[2], alias2);
411         assertIntermediateCa(getChain()[1], alias1);
412         assertRootCa(getChain()[2], alias2);
413         assertAliases(alias1, alias2);
414         assertEquals(getChain()[2], store.findIssuer(getChain()[1]));
415         assertEquals(getChain()[1], store.findIssuer(getChain()[0]));
416 
417         X509Certificate[] expected = getChain();
418         List<X509Certificate> actualList = store.getCertificateChain(expected[0]);
419 
420         assertEquals("Generated CA list should be same length", expected.length, actualList.size());
421         for (int i = 0; i < expected.length; i++) {
422             assertEquals("Chain value should be the same for position " + i, expected[i],
423                     actualList.get(i));
424         }
425         resetStore();
426     }
427 
testMissingSystemDirectory()428     public void testMissingSystemDirectory() throws Exception {
429         cleanStore();
430         createStore();
431         assertEmpty();
432     }
433 
testWithExistingUserDirectories()434     public void testWithExistingUserDirectories() throws Exception {
435         dirAdded.mkdirs();
436         dirDeleted.mkdirs();
437         install(getCa1(), getAliasSystemCa1());
438         assertRootCa(getCa1(), getAliasSystemCa1());
439         assertAliases(getAliasSystemCa1());
440     }
441 
testIsTrustAnchorWithReissuedgetCa()442     public void testIsTrustAnchorWithReissuedgetCa() throws Exception {
443         PublicKey publicKey = getPrivate().getCertificate().getPublicKey();
444         PrivateKey privateKey = getPrivate().getPrivateKey();
445         String name = "CN=CA4";
446         X509Certificate ca1 = TestKeyStore.createCa(publicKey, privateKey, name);
447         Thread.sleep(1 * 1000); // wait to ensure CAs vary by expiration
448         X509Certificate ca2 = TestKeyStore.createCa(publicKey, privateKey, name);
449         assertFalse(ca1.equals(ca2));
450 
451         String systemAlias = alias(false, ca1, 0);
452         install(ca1, systemAlias);
453         assertRootCa(ca1, systemAlias);
454         assertEquals(ca1, store.getTrustAnchor(ca2));
455         assertEquals(ca1, store.findIssuer(ca2));
456         resetStore();
457 
458         String userAlias = alias(true, ca1, 0);
459         store.installCertificate(ca1);
460         assertRootCa(ca1, userAlias);
461         assertNotNull(store.getTrustAnchor(ca2));
462         assertEquals(ca1, store.findIssuer(ca2));
463         resetStore();
464     }
465 
testInstallEmpty()466     public void testInstallEmpty() throws Exception {
467         store.installCertificate(getCa1());
468         assertRootCa(getCa1(), getAliasUserCa1());
469         assertAliases(getAliasUserCa1());
470 
471         // reinstalling should not change anything
472         store.installCertificate(getCa1());
473         assertRootCa(getCa1(), getAliasUserCa1());
474         assertAliases(getAliasUserCa1());
475     }
476 
testInstallEmptySystemExists()477     public void testInstallEmptySystemExists() throws Exception {
478         install(getCa1(), getAliasSystemCa1());
479         assertRootCa(getCa1(), getAliasSystemCa1());
480         assertAliases(getAliasSystemCa1());
481 
482         // reinstalling should not affect system CA
483         store.installCertificate(getCa1());
484         assertRootCa(getCa1(), getAliasSystemCa1());
485         assertAliases(getAliasSystemCa1());
486 
487     }
488 
testInstallEmptyDeletedSystemExists()489     public void testInstallEmptyDeletedSystemExists() throws Exception {
490         install(getCa1(), getAliasSystemCa1());
491         store.deleteCertificateEntry(getAliasSystemCa1());
492         assertEmpty();
493         assertDeleted(getCa1(), getAliasSystemCa1());
494 
495         // installing should restore deleted system CA
496         store.installCertificate(getCa1());
497         assertRootCa(getCa1(), getAliasSystemCa1());
498         assertAliases(getAliasSystemCa1());
499     }
500 
testDeleteEmpty()501     public void testDeleteEmpty() throws Exception {
502         store.deleteCertificateEntry(getAliasSystemCa1());
503         assertEmpty();
504         assertDeleted(getCa1(), getAliasSystemCa1());
505     }
506 
testDeleteUser()507     public void testDeleteUser() throws Exception {
508         store.installCertificate(getCa1());
509         assertRootCa(getCa1(), getAliasUserCa1());
510         assertAliases(getAliasUserCa1());
511 
512         store.deleteCertificateEntry(getAliasUserCa1());
513         assertEmpty();
514         assertDeleted(getCa1(), getAliasUserCa1());
515         assertNoTombstone(getAliasUserCa1());
516     }
517 
testDeleteSystem()518     public void testDeleteSystem() throws Exception {
519         install(getCa1(), getAliasSystemCa1());
520         assertRootCa(getCa1(), getAliasSystemCa1());
521         assertAliases(getAliasSystemCa1());
522 
523         store.deleteCertificateEntry(getAliasSystemCa1());
524         assertEmpty();
525         assertDeleted(getCa1(), getAliasSystemCa1());
526 
527         // deleting again should not change anything
528         store.deleteCertificateEntry(getAliasSystemCa1());
529         assertEmpty();
530         assertDeleted(getCa1(), getAliasSystemCa1());
531     }
532 
testIsUserAddedCertificate()533     public void testIsUserAddedCertificate() throws Exception {
534         assertFalse(store.isUserAddedCertificate(getCa1()));
535         assertFalse(store.isUserAddedCertificate(getCa2()));
536         install(getCa1(), getAliasSystemCa1());
537         assertFalse(store.isUserAddedCertificate(getCa1()));
538         assertFalse(store.isUserAddedCertificate(getCa2()));
539         install(getCa1(), getAliasUserCa1());
540         assertTrue(store.isUserAddedCertificate(getCa1()));
541         assertFalse(store.isUserAddedCertificate(getCa2()));
542         install(getCa2(), getAliasUserCa2());
543         assertTrue(store.isUserAddedCertificate(getCa1()));
544         assertTrue(store.isUserAddedCertificate(getCa2()));
545         store.deleteCertificateEntry(getAliasUserCa1());
546         assertFalse(store.isUserAddedCertificate(getCa1()));
547         assertTrue(store.isUserAddedCertificate(getCa2()));
548         store.deleteCertificateEntry(getAliasUserCa2());
549         assertFalse(store.isUserAddedCertificate(getCa1()));
550         assertFalse(store.isUserAddedCertificate(getCa2()));
551     }
552 
assertRootCa(X509Certificate x, String alias)553     private void assertRootCa(X509Certificate x, String alias) {
554         assertIntermediateCa(x, alias);
555         assertEquals(x, store.findIssuer(x));
556     }
557 
assertTrusted(X509Certificate x, String alias)558     private void assertTrusted(X509Certificate x, String alias) {
559         assertEquals(x, store.getCertificate(alias));
560         assertEquals(file(alias).lastModified(), store.getCreationDate(alias).getTime());
561         assertTrue(store.containsAlias(alias));
562         assertEquals(x, store.getTrustAnchor(x));
563     }
564 
assertIntermediateCa(X509Certificate x, String alias)565     private void assertIntermediateCa(X509Certificate x, String alias) {
566         assertTrusted(x, alias);
567         assertEquals(alias, store.getCertificateAlias(x));
568     }
569 
assertMasked(X509Certificate x, String alias)570     private void assertMasked(X509Certificate x, String alias) {
571         assertTrusted(x, alias);
572         assertFalse(alias.equals(store.getCertificateAlias(x)));
573     }
574 
assertDeleted(X509Certificate x, String alias)575     private void assertDeleted(X509Certificate x, String alias) {
576         assertNull(store.getCertificate(alias));
577         assertFalse(store.containsAlias(alias));
578         assertNull(store.getCertificateAlias(x));
579         assertNull(store.getTrustAnchor(x));
580         assertEquals(store.allSystemAliases().contains(alias),
581                      store.getCertificate(alias, true) != null);
582     }
583 
assertTombstone(String alias)584     private void assertTombstone(String alias) {
585         assertTrue(TrustedCertificateStore.isUser(alias));
586         File file = file(alias);
587         assertTrue(file.exists());
588         assertEquals(0, file.length());
589     }
590 
assertNoTombstone(String alias)591     private void assertNoTombstone(String alias) {
592         assertTrue(TrustedCertificateStore.isUser(alias));
593         assertFalse(file(alias).exists());
594     }
595 
assertAliases(String... aliases)596     private void assertAliases(String... aliases) {
597         Set<String> expected = new HashSet<String>(Arrays.asList(aliases));
598         Set<String> actual = new HashSet<String>();
599         for (String alias : store.aliases()) {
600             boolean system = TrustedCertificateStore.isSystem(alias);
601             boolean user = TrustedCertificateStore.isUser(alias);
602             if (system || user) {
603                 assertEquals(system, store.allSystemAliases().contains(alias));
604                 assertEquals(user, store.userAliases().contains(alias));
605                 actual.add(alias);
606             } else {
607                 throw new AssertionError(alias);
608             }
609         }
610         assertEquals(expected, actual);
611     }
612 
613     /**
614      * format a certificate alias
615      */
alias(boolean user, X509Certificate x, int index)616     private static String alias(boolean user, X509Certificate x, int index) {
617         String prefix = user ? "user:" : "system:";
618 
619         X500Principal subject = x.getSubjectX500Principal();
620         int intHash = NativeCrypto.X509_NAME_hash_old(subject);
621         String strHash = IntegralToString.intToHexString(intHash, false, 8);
622 
623         return prefix + strHash + '.' + index;
624     }
625 
626     /**
627      * Install certificate under specified alias
628      */
install(X509Certificate x, String alias)629     private void install(X509Certificate x, String alias) {
630         try {
631             File file = file(alias);
632             file.getParentFile().mkdirs();
633             OutputStream out = new FileOutputStream(file);
634             out.write(x.getEncoded());
635             out.close();
636         } catch (Exception e) {
637             throw new RuntimeException(e);
638         }
639     }
640 
641     /**
642      * Compute file for an alias
643      */
file(String alias)644     private File file(String alias) {
645         File dir;
646         if (TrustedCertificateStore.isSystem(alias)) {
647             dir = dirSystem;
648         } else if (TrustedCertificateStore.isUser(alias)) {
649             dir = dirAdded;
650         } else {
651             throw new IllegalArgumentException(alias);
652         }
653 
654         int index = alias.lastIndexOf(":");
655         if (index == -1) {
656             throw new IllegalArgumentException(alias);
657         }
658         String filename = alias.substring(index+1);
659 
660         return new File(dir, filename);
661     }
662 }
663