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 com.android.org.bouncycastle.asn1.x509.KeyPurposeId; 20import java.security.InvalidAlgorithmParameterException; 21import java.security.KeyStore.PrivateKeyEntry; 22import java.security.KeyStore; 23import java.security.Provider; 24import java.security.Security; 25import java.security.cert.CertificateException; 26import java.security.cert.PKIXBuilderParameters; 27import java.security.cert.PKIXParameters; 28import java.security.cert.X509CertSelector; 29import java.security.cert.X509Certificate; 30import java.util.Set; 31import javax.net.ssl.CertPathTrustManagerParameters; 32import javax.net.ssl.ManagerFactoryParameters; 33import javax.net.ssl.TrustManager; 34import javax.net.ssl.TrustManagerFactory; 35import javax.net.ssl.X509TrustManager; 36import junit.framework.TestCase; 37import libcore.java.security.StandardNames; 38import libcore.java.security.TestKeyStore; 39 40public class TrustManagerFactoryTest extends TestCase { 41 42 private static final String [] KEY_TYPES = new String[] { "RSA", "DSA", "EC", "EC_RSA" }; 43 44 private static TestKeyStore TEST_KEY_STORE; 45 46 // note the rare usage of DSA keys here in addition to RSA 47 private static TestKeyStore getTestKeyStore() throws Exception { 48 if (TEST_KEY_STORE == null) { 49 TEST_KEY_STORE = new TestKeyStore.Builder() 50 .keyAlgorithms(KEY_TYPES) 51 .aliasPrefix("rsa-dsa-ec") 52 .build(); 53 } 54 return TEST_KEY_STORE; 55 } 56 57 private static boolean supportsManagerFactoryParameters(String algorithm) { 58 return (StandardNames.IS_RI && algorithm.equals("PKIX")); 59 } 60 61 public void test_TrustManagerFactory_getDefaultAlgorithm() throws Exception { 62 String algorithm = TrustManagerFactory.getDefaultAlgorithm(); 63 assertEquals(StandardNames.TRUST_MANAGER_FACTORY_DEFAULT, algorithm); 64 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); 65 test_TrustManagerFactory(tmf); 66 } 67 68 private static class UselessManagerFactoryParameters implements ManagerFactoryParameters {} 69 70 private void test_TrustManagerFactory(TrustManagerFactory tmf) 71 throws Exception { 72 assertNotNull(tmf); 73 assertNotNull(tmf.getAlgorithm()); 74 assertNotNull(tmf.getProvider()); 75 76 // before init 77 try { 78 tmf.getTrustManagers(); 79 fail(); 80 } catch (IllegalStateException expected) { 81 } 82 83 // init with null ManagerFactoryParameters 84 try { 85 tmf.init((ManagerFactoryParameters) null); 86 fail(); 87 } catch (InvalidAlgorithmParameterException expected) { 88 } 89 90 // init with useless ManagerFactoryParameters 91 try { 92 tmf.init(new UselessManagerFactoryParameters()); 93 fail(); 94 } catch (InvalidAlgorithmParameterException expected) { 95 } 96 97 // init with PKIXParameters ManagerFactoryParameters 98 try { 99 PKIXParameters pp = new PKIXParameters(getTestKeyStore().keyStore); 100 CertPathTrustManagerParameters cptmp = new CertPathTrustManagerParameters(pp); 101 tmf.init(cptmp); 102 fail(); 103 } catch (InvalidAlgorithmParameterException expected) { 104 } 105 106 // init with PKIXBuilderParameters ManagerFactoryParameters 107 X509CertSelector xcs = new X509CertSelector(); 108 PKIXBuilderParameters pbp = new PKIXBuilderParameters(getTestKeyStore().keyStore, xcs); 109 CertPathTrustManagerParameters cptmp = new CertPathTrustManagerParameters(pbp); 110 if (supportsManagerFactoryParameters(tmf.getAlgorithm())) { 111 tmf.init(cptmp); 112 test_TrustManagerFactory_getTrustManagers(tmf); 113 } else { 114 try { 115 tmf.init(cptmp); 116 fail(); 117 } catch (InvalidAlgorithmParameterException expected) { 118 } 119 } 120 121 // init with null for default KeyStore 122 tmf.init((KeyStore) null); 123 test_TrustManagerFactory_getTrustManagers(tmf); 124 125 // init with specific key store 126 tmf.init(getTestKeyStore().keyStore); 127 test_TrustManagerFactory_getTrustManagers(tmf); 128 } 129 130 private void test_TrustManagerFactory_getTrustManagers(TrustManagerFactory tmf) 131 throws Exception { 132 TrustManager[] trustManagers = tmf.getTrustManagers(); 133 assertNotNull(trustManagers); 134 assertTrue(trustManagers.length > 0); 135 for (TrustManager trustManager : trustManagers) { 136 assertNotNull(trustManager); 137 if (trustManager instanceof X509TrustManager) { 138 test_X509TrustManager((X509TrustManager) trustManager); 139 } 140 } 141 } 142 143 private void test_X509TrustManager(X509TrustManager tm) throws Exception { 144 for (String keyType : KEY_TYPES) { 145 X509Certificate[] issuers = tm.getAcceptedIssuers(); 146 assertNotNull(issuers); 147 assertTrue(issuers.length > 1); 148 assertNotSame(issuers, tm.getAcceptedIssuers()); 149 boolean defaultTrustManager 150 // RI de-duplicates certs from TrustedCertificateEntry and PrivateKeyEntry 151 = issuers.length > (StandardNames.IS_RI ? 1 : 2) * KEY_TYPES.length; 152 153 String keyAlgName = TestKeyStore.keyAlgorithm(keyType); 154 String sigAlgName = TestKeyStore.signatureAlgorithm(keyType); 155 PrivateKeyEntry pke = getTestKeyStore().getPrivateKey(keyAlgName, sigAlgName); 156 X509Certificate[] chain = (X509Certificate[]) pke.getCertificateChain(); 157 if (defaultTrustManager) { 158 try { 159 tm.checkClientTrusted(chain, keyType); 160 fail(); 161 } catch (CertificateException expected) { 162 } 163 try { 164 tm.checkServerTrusted(chain, keyType); 165 fail(); 166 } catch (CertificateException expected) { 167 } 168 } else { 169 tm.checkClientTrusted(chain, keyType); 170 tm.checkServerTrusted(chain, keyType); 171 } 172 173 } 174 } 175 176 public void test_TrustManagerFactory_getInstance() throws Exception { 177 Provider[] providers = Security.getProviders(); 178 for (Provider provider : providers) { 179 Set<Provider.Service> services = provider.getServices(); 180 for (Provider.Service service : services) { 181 String type = service.getType(); 182 if (!type.equals("TrustManagerFactory")) { 183 continue; 184 } 185 String algorithm = service.getAlgorithm(); 186 { 187 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); 188 assertEquals(algorithm, tmf.getAlgorithm()); 189 test_TrustManagerFactory(tmf); 190 } 191 192 { 193 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm, 194 provider); 195 assertEquals(algorithm, tmf.getAlgorithm()); 196 assertEquals(provider, tmf.getProvider()); 197 test_TrustManagerFactory(tmf); 198 } 199 200 { 201 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm, 202 provider.getName()); 203 assertEquals(algorithm, tmf.getAlgorithm()); 204 assertEquals(provider, tmf.getProvider()); 205 test_TrustManagerFactory(tmf); 206 } 207 } 208 } 209 } 210 211 public void test_TrustManagerFactory_intermediate() throws Exception { 212 // chain should be server/intermediate/root 213 PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); 214 X509Certificate[] chain = (X509Certificate[])pke.getCertificateChain(); 215 assertEquals(3, chain.length); 216 217 // keyStore should contain only the intermediate CA so we can 218 // test proper validation even if there are extra certs after 219 // the trusted one (in this case the original root is "extra") 220 KeyStore keyStore = TestKeyStore.createKeyStore(); 221 keyStore.setCertificateEntry("alias", chain[1]); 222 223 Provider[] providers = Security.getProviders(); 224 for (Provider provider : providers) { 225 Set<Provider.Service> services = provider.getServices(); 226 for (Provider.Service service : services) { 227 String type = service.getType(); 228 if (!type.equals("TrustManagerFactory")) { 229 continue; 230 } 231 String algorithm = service.getAlgorithm(); 232 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); 233 tmf.init(keyStore); 234 TrustManager[] trustManagers = tmf.getTrustManagers(); 235 for (TrustManager trustManager : trustManagers) { 236 if (!(trustManager instanceof X509TrustManager)) { 237 continue; 238 } 239 X509TrustManager tm = (X509TrustManager) trustManager; 240 tm.checkClientTrusted(chain, "RSA"); 241 tm.checkServerTrusted(chain, "RSA"); 242 } 243 } 244 } 245 } 246 247 public void test_TrustManagerFactory_keyOnly() throws Exception { 248 // create a KeyStore containing only a private key with chain. 249 // unlike PKIXParameters(KeyStore), the cert chain of the key should be trusted. 250 KeyStore ks = TestKeyStore.createKeyStore(); 251 KeyStore.PrivateKeyEntry pke = getTestKeyStore().getPrivateKey("RSA", "RSA"); 252 ks.setKeyEntry("key", pke.getPrivateKey(), "pw".toCharArray(), pke.getCertificateChain()); 253 254 String algorithm = TrustManagerFactory.getDefaultAlgorithm(); 255 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); 256 tmf.init(ks); 257 X509TrustManager trustManager = (X509TrustManager) tmf.getTrustManagers()[0]; 258 trustManager.checkServerTrusted((X509Certificate[]) pke.getCertificateChain(), "RSA"); 259 } 260 261 public void test_TrustManagerFactory_extendedKeyUsage() throws Exception { 262 // anyExtendedKeyUsage should work for client or server 263 test_TrustManagerFactory_extendedKeyUsage(KeyPurposeId.anyExtendedKeyUsage, false, true, true); 264 test_TrustManagerFactory_extendedKeyUsage(KeyPurposeId.anyExtendedKeyUsage, true, true, true); 265 266 // critical clientAuth should work for client 267 test_TrustManagerFactory_extendedKeyUsage(KeyPurposeId.id_kp_clientAuth, false, true, false); 268 test_TrustManagerFactory_extendedKeyUsage(KeyPurposeId.id_kp_clientAuth, true, true, false); 269 270 // critical serverAuth should work for server 271 test_TrustManagerFactory_extendedKeyUsage(KeyPurposeId.id_kp_serverAuth, false, false, true); 272 test_TrustManagerFactory_extendedKeyUsage(KeyPurposeId.id_kp_serverAuth, true, false, true); 273 274 // codeSigning should not work 275 test_TrustManagerFactory_extendedKeyUsage(KeyPurposeId.id_kp_codeSigning, false, false, false); 276 test_TrustManagerFactory_extendedKeyUsage(KeyPurposeId.id_kp_codeSigning, true, false, false); 277 } 278 279 private void test_TrustManagerFactory_extendedKeyUsage(KeyPurposeId keyPurposeId, 280 boolean critical, 281 boolean client, 282 boolean server) 283 throws Exception { 284 String algorithm = "RSA"; 285 TestKeyStore intermediateCa = TestKeyStore.getIntermediateCa(); 286 TestKeyStore leaf = new TestKeyStore.Builder() 287 .keyAlgorithms(new String[] { algorithm }) 288 .aliasPrefix("criticalCodeSigning") 289 .signer(intermediateCa.getPrivateKey("RSA", "RSA")) 290 .rootCa(intermediateCa.getRootCertificate("RSA")) 291 .addExtendedKeyUsage(keyPurposeId, critical) 292 .build(); 293 // leaf.dump("test_TrustManagerFactory_criticalCodeSigning"); 294 PrivateKeyEntry privateKeyEntry = leaf.getPrivateKey(algorithm, algorithm); 295 X509Certificate[] chain = (X509Certificate[]) privateKeyEntry.getCertificateChain(); 296 297 TestKeyStore rootCa = TestKeyStore.getRootCa(); 298 X509TrustManager trustManager = (X509TrustManager) rootCa.trustManagers[0]; 299 try { 300 trustManager.checkClientTrusted(chain, algorithm); 301 assertTrue(client); 302 } catch (Exception e) { 303 assertFalse(client); 304 } 305 try { 306 trustManager.checkServerTrusted(chain, algorithm); 307 assertTrue(server); 308 } catch (Exception e) { 309 assertFalse(server); 310 } 311 } 312} 313