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