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