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