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