Home | History | Annotate | Download | only in conscrypt
      1 /* GENERATED SOURCE. DO NOT MODIFY. */
      2 /*
      3  * Copyright (C) 2011 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package com.android.org.conscrypt;
     19 
     20 import static org.junit.Assert.assertEquals;
     21 import static org.junit.Assert.assertTrue;
     22 import static org.junit.Assert.fail;
     23 
     24 import java.io.IOException;
     25 import java.security.KeyStore;
     26 import java.security.Principal;
     27 import java.security.cert.Certificate;
     28 import java.security.cert.CertificateException;
     29 import java.security.cert.X509Certificate;
     30 import java.util.Arrays;
     31 import java.util.List;
     32 import javax.net.ssl.HandshakeCompletedListener;
     33 import javax.net.ssl.HttpsURLConnection;
     34 import javax.net.ssl.SSLParameters;
     35 import javax.net.ssl.SSLPeerUnverifiedException;
     36 import javax.net.ssl.SSLSession;
     37 import javax.net.ssl.SSLSessionContext;
     38 import javax.net.ssl.SSLSocket;
     39 import javax.net.ssl.X509TrustManager;
     40 import com.android.org.conscrypt.java.security.TestKeyStore;
     41 import org.junit.Test;
     42 import org.junit.runner.RunWith;
     43 import org.junit.runners.JUnit4;
     44 
     45 /**
     46  * @hide This class is not part of the Android public SDK API
     47  */
     48 @RunWith(JUnit4.class)
     49 public class TrustManagerImplTest {
     50 
     51     /**
     52      * Ensure that our non-standard behavior of learning to trust new
     53      * intermediate CAs does not regress. http://b/3404902
     54      */
     55     @Test
     56     public void testLearnIntermediate() throws Exception {
     57         TestUtils.assumeExtendedTrustManagerAvailable();
     58         // chain3 should be server/intermediate/root
     59         KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
     60         X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain();
     61         X509Certificate root = chain3[2];
     62         X509Certificate intermediate = chain3[1];
     63         X509Certificate server = chain3[0];
     64         X509Certificate[] chain2 =  new X509Certificate[] { server, intermediate };
     65         X509Certificate[] chain1 =  new X509Certificate[] { server };
     66 
     67         // Normal behavior
     68         assertValid(chain3,   trustManager(root));
     69         assertValid(chain2,   trustManager(root));
     70         assertInvalid(chain1, trustManager(root));
     71         assertValid(chain3,   trustManager(intermediate));
     72         assertValid(chain2,   trustManager(intermediate));
     73         assertValid(chain1,   trustManager(intermediate));
     74         assertValid(chain3,   trustManager(server));
     75         assertValid(chain2,   trustManager(server));
     76         assertValid(chain1,   trustManager(server));
     77 
     78         // non-standard behavior
     79         X509TrustManager tm = trustManager(root);
     80         // fail on short chain with only root trusted
     81         assertInvalid(chain1, tm);
     82         // succeed on longer chain, learn intermediate
     83         assertValid(chain2, tm);
     84         // now we can validate the short chain
     85         assertValid(chain1, tm);
     86     }
     87 
     88     // We should ignore duplicate cruft in the certificate chain
     89     // See https://code.google.com/p/android/issues/detail?id=52295 http://b/8313312
     90     @Test
     91     public void testDuplicateInChain() throws Exception {
     92         TestUtils.assumeExtendedTrustManagerAvailable();
     93         // chain3 should be server/intermediate/root
     94         KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
     95         X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain();
     96         X509Certificate root = chain3[2];
     97         X509Certificate intermediate = chain3[1];
     98         X509Certificate server = chain3[0];
     99 
    100         X509Certificate[] chain4 = new X509Certificate[] { server, intermediate,
    101                                                            server, intermediate
    102         };
    103         assertValid(chain4, trustManager(root));
    104     }
    105 
    106     @Test
    107     public void testGetFullChain() throws Exception {
    108         TestUtils.assumeExtendedTrustManagerAvailable();
    109         // build the trust manager
    110         KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
    111         X509Certificate[] chain3 = (X509Certificate[]) pke.getCertificateChain();
    112         X509Certificate root = chain3[2];
    113         X509TrustManager tm = trustManager(root);
    114 
    115         // build the chains we'll use for testing
    116         X509Certificate intermediate = chain3[1];
    117         X509Certificate server = chain3[0];
    118         X509Certificate[] chain2 =  new X509Certificate[] { server, intermediate };
    119         X509Certificate[] chain1 =  new X509Certificate[] { server };
    120 
    121         assertTrue(tm instanceof TrustManagerImpl);
    122         TrustManagerImpl tmi = (TrustManagerImpl) tm;
    123         List<X509Certificate> certs =
    124                 tmi.checkServerTrusted(chain2, "RSA", new FakeSSLSession("purple.com"));
    125         assertEquals(Arrays.asList(chain3), certs);
    126         certs = tmi.checkServerTrusted(chain1, "RSA", new FakeSSLSession("purple.com"));
    127         assertEquals(Arrays.asList(chain3), certs);
    128     }
    129 
    130     @Test
    131     public void testHttpsEndpointIdentification() throws Exception {
    132         TestUtils.assumeExtendedTrustManagerAvailable();
    133 
    134         KeyStore.PrivateKeyEntry pke = TestKeyStore.getServerHostname().getPrivateKey("RSA", "RSA");
    135         X509Certificate[] chain = (X509Certificate[]) pke.getCertificateChain();
    136         X509Certificate root = chain[2];
    137         TrustManagerImpl tmi = (TrustManagerImpl) trustManager(root);
    138 
    139         String goodHostname = TestKeyStore.CERT_HOSTNAME;
    140         String badHostname = "definitelywrong.nopenopenope";
    141 
    142         // The default hostname verifier on OpenJDK rejects all hostnames, so use our own
    143         javax.net.ssl.HostnameVerifier oldDefault = HttpsURLConnection.getDefaultHostnameVerifier();
    144         try {
    145             HttpsURLConnection.setDefaultHostnameVerifier(new TestHostnameVerifier());
    146 
    147             SSLParameters params = new SSLParameters();
    148 
    149             // Without endpoint identification this should pass despite the mismatched hostname
    150             params.setEndpointIdentificationAlgorithm(null);
    151 
    152             List<X509Certificate> certs = tmi.getTrustedChainForServer(chain, "RSA",
    153                     new FakeSSLSocket(new FakeSSLSession(badHostname, chain), params));
    154             assertEquals(Arrays.asList(chain), certs);
    155 
    156             // Turn on endpoint identification
    157             params.setEndpointIdentificationAlgorithm("HTTPS");
    158 
    159             try {
    160                 tmi.getTrustedChainForServer(chain, "RSA",
    161                         new FakeSSLSocket(new FakeSSLSession(badHostname, chain), params));
    162             } catch (CertificateException expected) {
    163             }
    164 
    165             certs = tmi.getTrustedChainForServer(chain, "RSA",
    166                     new FakeSSLSocket(new FakeSSLSession(goodHostname, chain), params));
    167             assertEquals(Arrays.asList(chain), certs);
    168 
    169             // Override the global default hostname verifier with a Conscrypt-specific one that
    170             // always passes.  Both scenarios should pass.
    171             Conscrypt.setDefaultHostnameVerifier(new ConscryptHostnameVerifier() {
    172                 @Override
    173                 public boolean verify(String s, SSLSession sslSession) {
    174                     return true;
    175                 }
    176             });
    177 
    178             certs = tmi.getTrustedChainForServer(chain, "RSA",
    179                     new FakeSSLSocket(new FakeSSLSession(badHostname, chain), params));
    180             assertEquals(Arrays.asList(chain), certs);
    181 
    182             certs = tmi.getTrustedChainForServer(chain, "RSA",
    183                     new FakeSSLSocket(new FakeSSLSession(goodHostname, chain), params));
    184             assertEquals(Arrays.asList(chain), certs);
    185 
    186             // Now set an instance-specific verifier on the trust manager.  The bad hostname should
    187             // fail again.
    188             Conscrypt.setHostnameVerifier(tmi, new TestHostnameVerifier());
    189 
    190             try {
    191                 tmi.getTrustedChainForServer(chain, "RSA",
    192                         new FakeSSLSocket(new FakeSSLSession(badHostname, chain), params));
    193             } catch (CertificateException expected) {
    194             }
    195 
    196             certs = tmi.getTrustedChainForServer(chain, "RSA",
    197                     new FakeSSLSocket(new FakeSSLSession(goodHostname, chain), params));
    198             assertEquals(Arrays.asList(chain), certs);
    199 
    200             // Remove the instance-specific verifier, and both should pass again.
    201             Conscrypt.setHostnameVerifier(tmi, null);
    202 
    203             certs = tmi.getTrustedChainForServer(chain, "RSA",
    204                     new FakeSSLSocket(new FakeSSLSession(badHostname, chain), params));
    205             assertEquals(Arrays.asList(chain), certs);
    206 
    207             certs = tmi.getTrustedChainForServer(chain, "RSA",
    208                     new FakeSSLSocket(new FakeSSLSession(goodHostname, chain), params));
    209             assertEquals(Arrays.asList(chain), certs);
    210         } finally {
    211             Conscrypt.setDefaultHostnameVerifier(null);
    212             HttpsURLConnection.setDefaultHostnameVerifier(oldDefault);
    213         }
    214     }
    215 
    216     private X509TrustManager trustManager(X509Certificate ca) throws Exception {
    217         KeyStore keyStore = TestKeyStore.createKeyStore();
    218         keyStore.setCertificateEntry("alias", ca);
    219 
    220         return new TrustManagerImpl(keyStore);
    221     }
    222 
    223     private void assertValid(X509Certificate[] chain, X509TrustManager tm) throws Exception {
    224         if (tm instanceof TrustManagerImpl) {
    225             TrustManagerImpl tmi = (TrustManagerImpl) tm;
    226             tmi.checkServerTrusted(chain, "RSA");
    227         }
    228         tm.checkServerTrusted(chain, "RSA");
    229     }
    230 
    231     private void assertInvalid(X509Certificate[] chain, X509TrustManager tm) {
    232         try {
    233             tm.checkClientTrusted(chain, "RSA");
    234             fail();
    235         } catch (CertificateException expected) {
    236             // Expected.
    237         }
    238         try {
    239             tm.checkServerTrusted(chain, "RSA");
    240             fail();
    241         } catch (CertificateException expected) {
    242             // Expected.
    243         }
    244     }
    245 
    246     private static class FakeSSLSession implements SSLSession {
    247         private final String hostname;
    248         private final X509Certificate[] peerCerts;
    249 
    250         FakeSSLSession(String hostname) {
    251             this.hostname = hostname;
    252             peerCerts = null;
    253         }
    254 
    255         FakeSSLSession(String hostname, X509Certificate[] peerCerts) {
    256             this.hostname = hostname;
    257             this.peerCerts = peerCerts.clone();
    258         }
    259 
    260         @Override
    261         public int getApplicationBufferSize() {
    262             throw new UnsupportedOperationException();
    263         }
    264 
    265         @Override
    266         public String getCipherSuite() {
    267             throw new UnsupportedOperationException();
    268         }
    269 
    270         @Override
    271         public long getCreationTime() {
    272             throw new UnsupportedOperationException();
    273         }
    274 
    275         @Override
    276         public byte[] getId() {
    277             throw new UnsupportedOperationException();
    278         }
    279 
    280         @Override
    281         public long getLastAccessedTime() {
    282             throw new UnsupportedOperationException();
    283         }
    284 
    285         @Override
    286         public Certificate[] getLocalCertificates() {
    287             throw new UnsupportedOperationException();
    288         }
    289 
    290         @Override
    291         public Principal getLocalPrincipal() {
    292             throw new UnsupportedOperationException();
    293         }
    294 
    295         @Override
    296         public int getPacketBufferSize() {
    297             throw new UnsupportedOperationException();
    298         }
    299 
    300         @Override
    301         public javax.security.cert.X509Certificate[] getPeerCertificateChain()
    302                 throws SSLPeerUnverifiedException {
    303             throw new UnsupportedOperationException();
    304         }
    305 
    306         @Override
    307         public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
    308             if (peerCerts == null) {
    309                 throw new SSLPeerUnverifiedException("Null peerCerts");
    310             } else {
    311                 return peerCerts.clone();
    312             }
    313         }
    314 
    315         @Override
    316         public String getPeerHost() {
    317             return hostname;
    318         }
    319 
    320         @Override
    321         public int getPeerPort() {
    322             throw new UnsupportedOperationException();
    323         }
    324 
    325         @Override
    326         public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
    327             throw new UnsupportedOperationException();
    328         }
    329 
    330         @Override
    331         public String getProtocol() {
    332             throw new UnsupportedOperationException();
    333         }
    334 
    335         @Override
    336         public SSLSessionContext getSessionContext() {
    337             throw new UnsupportedOperationException();
    338         }
    339 
    340         @Override
    341         public Object getValue(String name) {
    342             throw new UnsupportedOperationException();
    343         }
    344 
    345         @Override
    346         public String[] getValueNames() {
    347             throw new UnsupportedOperationException();
    348         }
    349 
    350         @Override
    351         public void invalidate() {
    352             throw new UnsupportedOperationException();
    353         }
    354 
    355         @Override
    356         public boolean isValid() {
    357             throw new UnsupportedOperationException();
    358         }
    359 
    360         @Override
    361         public void putValue(String name, Object value) {
    362             throw new UnsupportedOperationException();
    363         }
    364 
    365         @Override
    366         public void removeValue(String name) {
    367             throw new UnsupportedOperationException();
    368         }
    369     }
    370 
    371     private static class FakeSSLSocket extends SSLSocket {
    372         private final SSLSession session;
    373         private final SSLParameters parameters;
    374 
    375         public FakeSSLSocket(SSLSession session, SSLParameters parameters) {
    376             this.session = session;
    377             this.parameters = parameters;
    378         }
    379 
    380         @Override
    381         public SSLParameters getSSLParameters() {
    382             return parameters;
    383         }
    384 
    385         @Override
    386         public String[] getSupportedCipherSuites() {
    387             throw new UnsupportedOperationException();
    388         }
    389 
    390         @Override
    391         public String[] getEnabledCipherSuites() {
    392             throw new UnsupportedOperationException();
    393         }
    394 
    395         @Override
    396         public void setEnabledCipherSuites(String[] strings) {
    397             throw new UnsupportedOperationException();
    398         }
    399 
    400         @Override
    401         public String[] getSupportedProtocols() {
    402             throw new UnsupportedOperationException();
    403         }
    404 
    405         @Override
    406         public String[] getEnabledProtocols() {
    407             throw new UnsupportedOperationException();
    408         }
    409 
    410         @Override
    411         public void setEnabledProtocols(String[] strings) {
    412             throw new UnsupportedOperationException();
    413         }
    414 
    415         @Override
    416         public SSLSession getSession() {
    417             return session;
    418         }
    419 
    420         @Override
    421         public SSLSession getHandshakeSession() {
    422             return session;
    423         }
    424 
    425         @Override
    426         public void addHandshakeCompletedListener(
    427                 HandshakeCompletedListener handshakeCompletedListener) {
    428             throw new UnsupportedOperationException();
    429         }
    430 
    431         @Override
    432         public void removeHandshakeCompletedListener(
    433                 HandshakeCompletedListener handshakeCompletedListener) {
    434             throw new UnsupportedOperationException();
    435         }
    436 
    437         @Override
    438         public void startHandshake() throws IOException {
    439             throw new UnsupportedOperationException();
    440         }
    441 
    442         @Override
    443         public void setUseClientMode(boolean b) {
    444             throw new UnsupportedOperationException();
    445         }
    446 
    447         @Override
    448         public boolean getUseClientMode() {
    449             throw new UnsupportedOperationException();
    450         }
    451 
    452         @Override
    453         public void setNeedClientAuth(boolean b) {
    454             throw new UnsupportedOperationException();
    455         }
    456 
    457         @Override
    458         public boolean getNeedClientAuth() {
    459             throw new UnsupportedOperationException();
    460         }
    461 
    462         @Override
    463         public void setWantClientAuth(boolean b) {
    464             throw new UnsupportedOperationException();
    465         }
    466 
    467         @Override
    468         public boolean getWantClientAuth() {
    469             throw new UnsupportedOperationException();
    470         }
    471 
    472         @Override
    473         public void setEnableSessionCreation(boolean b) {
    474             throw new UnsupportedOperationException();
    475         }
    476 
    477         @Override
    478         public boolean getEnableSessionCreation() {
    479             throw new UnsupportedOperationException();
    480         }
    481     }
    482 
    483     private static class TestHostnameVerifier
    484             extends com.android.org.conscrypt.javax.net.ssl.TestHostnameVerifier
    485             implements ConscryptHostnameVerifier {}
    486 }
    487