KeyManagerFactoryTest.java revision 888373c54fd5f8fa0b1965238309db8187e3b381
1/*
2 * Copyright (C) 2010 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 libcore.javax.net.ssl;
18
19import java.security.InvalidAlgorithmParameterException;
20import java.security.KeyStore.Builder;
21import java.security.KeyStore.PasswordProtection;
22import java.security.KeyStore.PrivateKeyEntry;
23import java.security.PrivateKey;
24import java.security.Provider;
25import java.security.Security;
26import java.security.cert.Certificate;
27import java.security.cert.X509Certificate;
28import java.util.Arrays;
29import java.util.Set;
30import javax.net.ssl.KeyManager;
31import javax.net.ssl.KeyManagerFactory;
32import javax.net.ssl.KeyStoreBuilderParameters;
33import javax.net.ssl.ManagerFactoryParameters;
34import javax.net.ssl.X509ExtendedKeyManager;
35import javax.net.ssl.X509KeyManager;
36import junit.framework.TestCase;
37import libcore.java.security.StandardNames;
38import libcore.java.security.TestKeyStore;
39
40public class KeyManagerFactoryTest extends TestCase {
41
42    private static TestKeyStore TEST_KEY_STORE;
43
44    // note the rare usage of DSA keys here in addition to RSA
45    private static TestKeyStore getTestKeyStore() throws Exception {
46        if (TEST_KEY_STORE == null) {
47            TEST_KEY_STORE = new TestKeyStore.Builder()
48                    .keyAlgorithms("RSA", "DH_RSA", "DSA", "DH_DSA", "EC", "EC_RSA")
49                    .aliasPrefix("rsa-dsa-ec-dh")
50                    .build();
51        }
52        return TEST_KEY_STORE;
53    }
54
55    public void test_KeyManagerFactory_getDefaultAlgorithm() throws Exception {
56        String algorithm = KeyManagerFactory.getDefaultAlgorithm();
57        assertEquals(StandardNames.KEY_MANAGER_FACTORY_DEFAULT, algorithm);
58        KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
59        test_KeyManagerFactory(kmf);
60    }
61
62    private static class UselessManagerFactoryParameters implements ManagerFactoryParameters {}
63
64    private static boolean supportsManagerFactoryParameters(String algorithm) {
65        // Only the "New" one supports ManagerFactoryParameters
66        return algorithm.equals("NewSunX509");
67    }
68
69    private static String[] keyTypes(String algorithm) {
70        // Although the "New" one supports ManagerFactoryParameters,
71        // it can't handle nulls in the key types array.
72        return (algorithm.equals("NewSunX509")
73                ? KEY_TYPES_WITH_EMPTY
74                : KEY_TYPES_WITH_EMPTY_AND_NULL);
75    }
76
77    private void test_KeyManagerFactory(KeyManagerFactory kmf) throws Exception {
78        assertNotNull(kmf);
79        assertNotNull(kmf.getAlgorithm());
80        assertNotNull(kmf.getProvider());
81
82        // before init
83        try {
84            kmf.getKeyManagers();
85            fail();
86        } catch (IllegalStateException expected) {
87        }
88
89        // init with null ManagerFactoryParameters
90        try {
91            kmf.init(null);
92            fail();
93        } catch (InvalidAlgorithmParameterException expected) {
94        }
95
96        // init with useless ManagerFactoryParameters
97        try {
98            kmf.init(new UselessManagerFactoryParameters());
99            fail();
100        } catch (InvalidAlgorithmParameterException expected) {
101        }
102
103        // init with KeyStoreBuilderParameters ManagerFactoryParameters
104        PasswordProtection pp = new PasswordProtection(getTestKeyStore().storePassword);
105        Builder builder = Builder.newInstance(getTestKeyStore().keyStore, pp);
106        KeyStoreBuilderParameters ksbp = new KeyStoreBuilderParameters(builder);
107        if (supportsManagerFactoryParameters(kmf.getAlgorithm())) {
108            kmf.init(ksbp);
109            test_KeyManagerFactory_getKeyManagers(kmf, false);
110        } else {
111            try {
112                kmf.init(ksbp);
113                fail();
114            } catch (InvalidAlgorithmParameterException expected) {
115            }
116        }
117
118        // init with null for default behavior
119        kmf.init(null, null);
120        test_KeyManagerFactory_getKeyManagers(kmf, true);
121
122        // init with specific key store and password
123        kmf.init(getTestKeyStore().keyStore, getTestKeyStore().storePassword);
124        test_KeyManagerFactory_getKeyManagers(kmf, false);
125    }
126
127    private void test_KeyManagerFactory_getKeyManagers(KeyManagerFactory kmf, boolean empty)
128            throws Exception {
129        KeyManager[] keyManagers = kmf.getKeyManagers();
130        assertNotNull(keyManagers);
131        assertTrue(keyManagers.length > 0);
132        for (KeyManager keyManager : keyManagers) {
133            assertNotNull(keyManager);
134            if (keyManager instanceof X509KeyManager) {
135                test_X509KeyManager((X509KeyManager) keyManager, empty, kmf.getAlgorithm());
136            }
137        }
138    }
139
140    private static final String[] KEY_TYPES_ONLY
141            = StandardNames.KEY_TYPES.toArray(new String[StandardNames.KEY_TYPES.size()]);
142    private static final String[] KEY_TYPES_WITH_EMPTY
143            = new String[KEY_TYPES_ONLY.length + 1];
144    private static final String[] KEY_TYPES_WITH_EMPTY_AND_NULL
145            = new String[KEY_TYPES_ONLY.length + 2];
146    static {
147        System.arraycopy(KEY_TYPES_ONLY, 0,
148                         KEY_TYPES_WITH_EMPTY, 0,
149                         KEY_TYPES_ONLY.length);
150        KEY_TYPES_WITH_EMPTY[KEY_TYPES_WITH_EMPTY.length-1] = "";
151
152        System.arraycopy(KEY_TYPES_WITH_EMPTY, 0,
153                         KEY_TYPES_WITH_EMPTY_AND_NULL, 0,
154                         KEY_TYPES_WITH_EMPTY.length);
155        // extra null at end requires no initialization
156    }
157
158    private void test_X509KeyManager(X509KeyManager km, boolean empty, String algorithm)
159            throws Exception {
160        String[] keyTypes = keyTypes(algorithm);
161        for (String keyType : keyTypes) {
162            String[] aliases = km.getClientAliases(keyType, null);
163            if (empty || keyType == null || keyType.isEmpty()) {
164                assertNull(keyType, aliases);
165                continue;
166            }
167            assertNotNull(keyType, aliases);
168            for (String alias : aliases) {
169                test_X509KeyManager_alias(km, alias, keyType, false, empty);
170            }
171        }
172        for (String keyType : keyTypes) {
173            String[] aliases = km.getServerAliases(keyType, null);
174            if (empty || keyType == null || keyType.isEmpty()) {
175                assertNull(keyType, aliases);
176                continue;
177            }
178            assertNotNull(keyType, aliases);
179            for (String alias : aliases) {
180                test_X509KeyManager_alias(km, alias, keyType, false, empty);
181            }
182        }
183
184        String a = km.chooseClientAlias(keyTypes, null, null);
185        test_X509KeyManager_alias(km, a, null, true, empty);
186
187        for (String keyType : keyTypes) {
188            String[] array = new String[] { keyType };
189            String alias = km.chooseClientAlias(array, null, null);
190            test_X509KeyManager_alias(km, alias, keyType, false, empty);
191        }
192        for (String keyType : keyTypes) {
193            String alias = km.chooseServerAlias(keyType, null, null);
194            test_X509KeyManager_alias(km, alias, keyType, false, empty);
195        }
196        if (km instanceof X509ExtendedKeyManager) {
197            test_X509ExtendedKeyManager((X509ExtendedKeyManager) km, empty, algorithm);
198        }
199    }
200
201    private void test_X509ExtendedKeyManager(X509ExtendedKeyManager km,
202                                             boolean empty, String algorithm) throws Exception {
203        String[] keyTypes = keyTypes(algorithm);
204        String a = km.chooseEngineClientAlias(keyTypes, null, null);
205        test_X509KeyManager_alias(km, a, null, true, empty);
206        for (String keyType : keyTypes) {
207            String[] array = new String[] { keyType };
208            String alias = km.chooseEngineClientAlias(array, null, null);
209            test_X509KeyManager_alias(km, alias, keyType, false, empty);
210        }
211        for (String keyType : keyTypes) {
212            String alias = km.chooseEngineServerAlias(keyType, null, null);
213            test_X509KeyManager_alias(km, alias, keyType, false, empty);
214        }
215    }
216
217    private void test_X509KeyManager_alias(X509KeyManager km,
218                                           String alias,
219                                           String keyType,
220                                           boolean many,
221                                           boolean empty) throws Exception {
222        if (empty || (!many && (keyType == null || keyType.isEmpty()))) {
223            assertNull(keyType, alias);
224            assertNull(keyType, km.getCertificateChain(alias));
225            assertNull(keyType, km.getPrivateKey(alias));
226            return;
227        }
228        assertNotNull(keyType, alias);
229
230        X509Certificate[] certificateChain = km.getCertificateChain(alias);
231        PrivateKey privateKey = km.getPrivateKey(alias);
232
233        String keyAlgName;
234        String sigAlgName;
235        if (keyType == null) {
236            keyAlgName = privateKey.getAlgorithm();
237            sigAlgName = keyAlgName;
238        } else {
239            // potentially handle EC_EC or EC_RSA
240            keyAlgName = TestKeyStore.keyAlgorithm(keyType);
241            sigAlgName = TestKeyStore.signatureAlgorithm(keyType);
242            X509Certificate certificate = certificateChain[0];
243            assertEquals(keyType, keyAlgName, certificate.getPublicKey().getAlgorithm());
244            assertEquals(keyType, keyAlgName, privateKey.getAlgorithm());
245            // skip this for EC which could return EC_RSA case instead of EC_EC
246            if (!keyType.equals("EC")) {
247                String expectedSigAlgName = sigAlgName.toUpperCase();
248                String actualSigAlgName = certificate.getSigAlgName().toUpperCase();
249                String expected = actualSigAlgName + " contains " + expectedSigAlgName;
250                assertTrue(expected, actualSigAlgName.contains(expectedSigAlgName));
251            }
252        }
253
254        PrivateKeyEntry privateKeyEntry = getTestKeyStore().getPrivateKey(keyAlgName, sigAlgName);
255        if (!"EC".equals(keyAlgName)) {
256            assertEquals(keyType,
257                         Arrays.<Certificate>asList(privateKeyEntry.getCertificateChain()),
258                         Arrays.<Certificate>asList(certificateChain));
259            assertEquals(keyType,
260                         privateKeyEntry.getPrivateKey(), privateKey);
261        }
262    }
263
264    public void test_KeyManagerFactory_getInstance() throws Exception {
265        Provider[] providers = Security.getProviders();
266        for (Provider provider : providers) {
267            Set<Provider.Service> services = provider.getServices();
268            for (Provider.Service service : services) {
269                String type = service.getType();
270                if (!type.equals("KeyManagerFactory")) {
271                    continue;
272                }
273                String algorithm = service.getAlgorithm();
274                try {
275                    {
276                        KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
277                        assertEquals(algorithm, kmf.getAlgorithm());
278                        test_KeyManagerFactory(kmf);
279                    }
280
281                    {
282                        KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm,
283                                                                              provider);
284                        assertEquals(algorithm, kmf.getAlgorithm());
285                        assertEquals(provider, kmf.getProvider());
286                        test_KeyManagerFactory(kmf);
287                    }
288
289                    {
290                        KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm,
291                                                                              provider.getName());
292                        assertEquals(algorithm, kmf.getAlgorithm());
293                        assertEquals(provider, kmf.getProvider());
294                        test_KeyManagerFactory(kmf);
295                    }
296                } catch (Exception e) {
297                    throw new Exception("Problem with algorithm " + algorithm, e);
298                }
299            }
300        }
301    }
302}
303