1 /* 2 * Copyright (C) 2015 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 android.security.net.config; 18 19 import java.net.Socket; 20 import java.security.cert.CertificateException; 21 import java.security.cert.X509Certificate; 22 import java.util.List; 23 24 import javax.net.ssl.SSLSocket; 25 import javax.net.ssl.SSLEngine; 26 import javax.net.ssl.SSLSession; 27 import javax.net.ssl.X509ExtendedTrustManager; 28 29 /** 30 * {@link X509ExtendedTrustManager} based on an {@link ApplicationConfig}. 31 * 32 * <p>This trust manager delegates to the specific trust manager for the hostname being used for 33 * the connection (See {@link ApplicationConfig#getConfigForHostname(String)} and 34 * {@link NetworkSecurityTrustManager}).</p> 35 * 36 * Note that if the {@code ApplicationConfig} has per-domain configurations the hostname aware 37 * {@link #checkServerTrusted(X509Certificate[], String String)} must be used instead of the normal 38 * non-aware call. 39 * @hide */ 40 public class RootTrustManager extends X509ExtendedTrustManager { 41 private final ApplicationConfig mConfig; 42 RootTrustManager(ApplicationConfig config)43 public RootTrustManager(ApplicationConfig config) { 44 if (config == null) { 45 throw new NullPointerException("config must not be null"); 46 } 47 mConfig = config; 48 } 49 50 @Override checkClientTrusted(X509Certificate[] chain, String authType)51 public void checkClientTrusted(X509Certificate[] chain, String authType) 52 throws CertificateException { 53 // Use the default configuration for all client authentication. Domain specific configs are 54 // only for use in checking server trust not client trust. 55 NetworkSecurityConfig config = mConfig.getConfigForHostname(""); 56 config.getTrustManager().checkClientTrusted(chain, authType); 57 } 58 59 @Override checkClientTrusted(X509Certificate[] certs, String authType, Socket socket)60 public void checkClientTrusted(X509Certificate[] certs, String authType, Socket socket) 61 throws CertificateException { 62 // Use the default configuration for all client authentication. Domain specific configs are 63 // only for use in checking server trust not client trust. 64 NetworkSecurityConfig config = mConfig.getConfigForHostname(""); 65 config.getTrustManager().checkClientTrusted(certs, authType, socket); 66 } 67 68 @Override checkClientTrusted(X509Certificate[] certs, String authType, SSLEngine engine)69 public void checkClientTrusted(X509Certificate[] certs, String authType, SSLEngine engine) 70 throws CertificateException { 71 // Use the default configuration for all client authentication. Domain specific configs are 72 // only for use in checking server trust not client trust. 73 NetworkSecurityConfig config = mConfig.getConfigForHostname(""); 74 config.getTrustManager().checkClientTrusted(certs, authType, engine); 75 } 76 77 @Override checkServerTrusted(X509Certificate[] certs, String authType, Socket socket)78 public void checkServerTrusted(X509Certificate[] certs, String authType, Socket socket) 79 throws CertificateException { 80 if (socket instanceof SSLSocket) { 81 SSLSocket sslSocket = (SSLSocket) socket; 82 SSLSession session = sslSocket.getHandshakeSession(); 83 if (session == null) { 84 throw new CertificateException("Not in handshake; no session available"); 85 } 86 String host = session.getPeerHost(); 87 NetworkSecurityConfig config = mConfig.getConfigForHostname(host); 88 config.getTrustManager().checkServerTrusted(certs, authType, socket); 89 } else { 90 // Not an SSLSocket, use the hostname unaware checkServerTrusted. 91 checkServerTrusted(certs, authType); 92 } 93 } 94 95 @Override checkServerTrusted(X509Certificate[] certs, String authType, SSLEngine engine)96 public void checkServerTrusted(X509Certificate[] certs, String authType, SSLEngine engine) 97 throws CertificateException { 98 SSLSession session = engine.getHandshakeSession(); 99 if (session == null) { 100 throw new CertificateException("Not in handshake; no session available"); 101 } 102 String host = session.getPeerHost(); 103 NetworkSecurityConfig config = mConfig.getConfigForHostname(host); 104 config.getTrustManager().checkServerTrusted(certs, authType, engine); 105 } 106 107 @Override checkServerTrusted(X509Certificate[] certs, String authType)108 public void checkServerTrusted(X509Certificate[] certs, String authType) 109 throws CertificateException { 110 if (mConfig.hasPerDomainConfigs()) { 111 throw new CertificateException( 112 "Domain specific configurations require that hostname aware" 113 + " checkServerTrusted(X509Certificate[], String, String) is used"); 114 } 115 NetworkSecurityConfig config = mConfig.getConfigForHostname(""); 116 config.getTrustManager().checkServerTrusted(certs, authType); 117 } 118 119 /** 120 * Hostname aware version of {@link #checkServerTrusted(X509Certificate[], String)}. 121 * This interface is used by conscrypt and android.net.http.X509TrustManagerExtensions do not 122 * modify without modifying those callers. 123 */ checkServerTrusted(X509Certificate[] certs, String authType, String hostname)124 public List<X509Certificate> checkServerTrusted(X509Certificate[] certs, String authType, 125 String hostname) throws CertificateException { 126 if (hostname == null && mConfig.hasPerDomainConfigs()) { 127 throw new CertificateException( 128 "Domain specific configurations require that the hostname be provided"); 129 } 130 NetworkSecurityConfig config = mConfig.getConfigForHostname(hostname); 131 return config.getTrustManager().checkServerTrusted(certs, authType, hostname); 132 } 133 134 @Override getAcceptedIssuers()135 public X509Certificate[] getAcceptedIssuers() { 136 // getAcceptedIssuers is meant to be used to determine which trust anchors the server will 137 // accept when verifying clients. Domain specific configs are only for use in checking 138 // server trust not client trust so use the default config. 139 NetworkSecurityConfig config = mConfig.getConfigForHostname(""); 140 return config.getTrustManager().getAcceptedIssuers(); 141 } 142 143 /** 144 * Returns {@code true} if this trust manager uses the same trust configuration for the provided 145 * hostnames. 146 * 147 * <p>This is required by android.net.http.X509TrustManagerExtensions. 148 */ isSameTrustConfiguration(String hostname1, String hostname2)149 public boolean isSameTrustConfiguration(String hostname1, String hostname2) { 150 return mConfig.getConfigForHostname(hostname1) 151 .equals(mConfig.getConfigForHostname(hostname2)); 152 } 153 } 154