Home | History | Annotate | Download | only in ssl
      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