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