Home | History | Annotate | Download | only in conscrypt
      1 /*
      2  * Copyright (C) 2011 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;
     18 
     19 import java.security.KeyStore;
     20 import java.security.Principal;
     21 import java.security.cert.Certificate;
     22 import java.security.cert.CertificateException;
     23 import java.security.cert.X509Certificate;
     24 import java.util.Arrays;
     25 import java.util.List;
     26 import javax.net.ssl.SSLPeerUnverifiedException;
     27 import javax.net.ssl.SSLSession;
     28 import javax.net.ssl.SSLSessionContext;
     29 import javax.net.ssl.X509TrustManager;
     30 import junit.framework.TestCase;
     31 import org.conscrypt.java.security.TestKeyStore;
     32 
     33 public class TrustManagerImplTest extends TestCase {
     34 
     35     /**
     36      * Ensure that our non-standard behavior of learning to trust new
     37      * intermediate CAs does not regress. http://b/3404902
     38      */
     39     public void testLearnIntermediate() throws Exception {
     40         // chain3 should be server/intermediate/root
     41         KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
     42         X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain();
     43         X509Certificate root = chain3[2];
     44         X509Certificate intermediate = chain3[1];
     45         X509Certificate server = chain3[0];
     46         X509Certificate[] chain2 =  new X509Certificate[] { server, intermediate };
     47         X509Certificate[] chain1 =  new X509Certificate[] { server };
     48 
     49         // Normal behavior
     50         assertValid(chain3,   trustManager(root));
     51         assertValid(chain2,   trustManager(root));
     52         assertInvalid(chain1, trustManager(root));
     53         assertValid(chain3,   trustManager(intermediate));
     54         assertValid(chain2,   trustManager(intermediate));
     55         assertValid(chain1,   trustManager(intermediate));
     56         assertValid(chain3,   trustManager(server));
     57         assertValid(chain2,   trustManager(server));
     58         assertValid(chain1,   trustManager(server));
     59 
     60         // non-standard behavior
     61         X509TrustManager tm = trustManager(root);
     62         // fail on short chain with only root trusted
     63         assertInvalid(chain1, tm);
     64         // succeed on longer chain, learn intermediate
     65         assertValid(chain2, tm);
     66         // now we can validate the short chain
     67         assertValid(chain1, tm);
     68     }
     69 
     70     // We should ignore duplicate cruft in the certificate chain
     71     // See https://code.google.com/p/android/issues/detail?id=52295 http://b/8313312
     72     public void testDuplicateInChain() throws Exception {
     73         // chain3 should be server/intermediate/root
     74         KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
     75         X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain();
     76         X509Certificate root = chain3[2];
     77         X509Certificate intermediate = chain3[1];
     78         X509Certificate server = chain3[0];
     79 
     80         X509Certificate[] chain4 = new X509Certificate[] { server, intermediate,
     81                                                            server, intermediate
     82         };
     83         assertValid(chain4, trustManager(root));
     84     }
     85 
     86     public void testGetFullChain() throws Exception {
     87         // build the trust manager
     88         KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
     89         X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain();
     90         X509Certificate root = chain3[2];
     91         X509TrustManager tm = trustManager(root);
     92 
     93         // build the chains we'll use for testing
     94         X509Certificate intermediate = chain3[1];
     95         X509Certificate server = chain3[0];
     96         X509Certificate[] chain2 =  new X509Certificate[] { server, intermediate };
     97         X509Certificate[] chain1 =  new X509Certificate[] { server };
     98 
     99         assertTrue(tm instanceof TrustManagerImpl);
    100         TrustManagerImpl tmi = (TrustManagerImpl) tm;
    101         List<X509Certificate> certs = tmi.checkServerTrusted(chain2, "RSA", new MySSLSession(
    102                 "purple.com"));
    103         assertEquals(Arrays.asList(chain3), certs);
    104         certs = tmi.checkServerTrusted(chain1, "RSA", new MySSLSession("purple.com"));
    105         assertEquals(Arrays.asList(chain3), certs);
    106     }
    107 
    108 
    109     private X509TrustManager trustManager(X509Certificate ca) throws Exception {
    110         KeyStore keyStore = TestKeyStore.createKeyStore();
    111         keyStore.setCertificateEntry("alias", ca);
    112 
    113         return new TrustManagerImpl(keyStore);
    114     }
    115 
    116     private void assertValid(X509Certificate[] chain, X509TrustManager tm) throws Exception {
    117         if (tm instanceof TrustManagerImpl) {
    118             TrustManagerImpl tmi = (TrustManagerImpl) tm;
    119             tmi.checkServerTrusted(chain, "RSA");
    120         }
    121         tm.checkServerTrusted(chain, "RSA");
    122     }
    123 
    124     private void assertInvalid(X509Certificate[] chain, X509TrustManager tm) {
    125         try {
    126             tm.checkClientTrusted(chain, "RSA");
    127             fail();
    128         } catch (CertificateException expected) {
    129             // Expected.
    130         }
    131         try {
    132             tm.checkServerTrusted(chain, "RSA");
    133             fail();
    134         } catch (CertificateException expected) {
    135             // Expected.
    136         }
    137     }
    138 
    139     private static class MySSLSession implements SSLSession {
    140         private final String hostname;
    141 
    142         MySSLSession(String hostname) {
    143             this.hostname = hostname;
    144         }
    145 
    146         @Override
    147         public int getApplicationBufferSize() {
    148             throw new UnsupportedOperationException();
    149         }
    150 
    151         @Override
    152         public String getCipherSuite() {
    153             throw new UnsupportedOperationException();
    154         }
    155 
    156         @Override
    157         public long getCreationTime() {
    158             throw new UnsupportedOperationException();
    159         }
    160 
    161         @Override
    162         public byte[] getId() {
    163             throw new UnsupportedOperationException();
    164         }
    165 
    166         @Override
    167         public long getLastAccessedTime() {
    168             throw new UnsupportedOperationException();
    169         }
    170 
    171         @Override
    172         public Certificate[] getLocalCertificates() {
    173             throw new UnsupportedOperationException();
    174         }
    175 
    176         @Override
    177         public Principal getLocalPrincipal() {
    178             throw new UnsupportedOperationException();
    179         }
    180 
    181         @Override
    182         public int getPacketBufferSize() {
    183             throw new UnsupportedOperationException();
    184         }
    185 
    186         @Override
    187         public javax.security.cert.X509Certificate[] getPeerCertificateChain()
    188                 throws SSLPeerUnverifiedException {
    189             throw new UnsupportedOperationException();
    190         }
    191 
    192         @Override
    193         public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
    194             throw new UnsupportedOperationException();
    195         }
    196 
    197         @Override
    198         public String getPeerHost() {
    199             return hostname;
    200         }
    201 
    202         @Override
    203         public int getPeerPort() {
    204             throw new UnsupportedOperationException();
    205         }
    206 
    207         @Override
    208         public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
    209             throw new UnsupportedOperationException();
    210         }
    211 
    212         @Override
    213         public String getProtocol() {
    214             throw new UnsupportedOperationException();
    215         }
    216 
    217         @Override
    218         public SSLSessionContext getSessionContext() {
    219             throw new UnsupportedOperationException();
    220         }
    221 
    222         @Override
    223         public Object getValue(String name) {
    224             throw new UnsupportedOperationException();
    225         }
    226 
    227         @Override
    228         public String[] getValueNames() {
    229             throw new UnsupportedOperationException();
    230         }
    231 
    232         @Override
    233         public void invalidate() {
    234             throw new UnsupportedOperationException();
    235         }
    236 
    237         @Override
    238         public boolean isValid() {
    239             throw new UnsupportedOperationException();
    240         }
    241 
    242         @Override
    243         public void putValue(String name, Object value) {
    244             throw new UnsupportedOperationException();
    245         }
    246 
    247         @Override
    248         public void removeValue(String name) {
    249             throw new UnsupportedOperationException();
    250         }
    251     }
    252 }
    253