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