• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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