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