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 java.security.InvalidAlgorithmParameterException;
     20 import java.security.KeyStore.Builder;
     21 import java.security.KeyStore.PasswordProtection;
     22 import java.security.KeyStore.PrivateKeyEntry;
     23 import java.security.PrivateKey;
     24 import java.security.Provider;
     25 import java.security.Security;
     26 import java.security.cert.Certificate;
     27 import java.security.cert.X509Certificate;
     28 import java.util.Arrays;
     29 import java.util.Set;
     30 import javax.net.ssl.KeyManager;
     31 import javax.net.ssl.KeyManagerFactory;
     32 import javax.net.ssl.KeyStoreBuilderParameters;
     33 import javax.net.ssl.ManagerFactoryParameters;
     34 import javax.net.ssl.X509ExtendedKeyManager;
     35 import javax.net.ssl.X509KeyManager;
     36 import junit.framework.TestCase;
     37 import libcore.java.security.StandardNames;
     38 import libcore.java.security.TestKeyStore;
     39 
     40 public 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", "DSA", "EC", "EC_RSA")
     49                     .aliasPrefix("rsa-dsa-ec")
     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