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", "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