• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 
27 package sun.security.ssl;
28 
29 import java.net.Socket;
30 import javax.net.ssl.SSLSession;
31 
32 import java.util.*;
33 import java.security.*;
34 import java.security.cert.*;
35 
36 import javax.net.ssl.*;
37 
38 import sun.security.validator.*;
39 
40 import sun.security.util.HostnameChecker;
41 
42 /**
43  * This class implements the SunJSSE X.509 trust manager using the internal
44  * validator API in J2SE core. The logic in this class is minimal.<p>
45  * <p>
46  * This class supports both the Simple validation algorithm from previous
47  * JSSE versions and PKIX validation. Currently, it is not possible for the
48  * application to specify PKIX parameters other than trust anchors. This will
49  * be fixed in a future release using new APIs. When that happens, it may also
50  * make sense to separate the Simple and PKIX trust managers into separate
51  * classes.
52  *
53  * @author Andreas Sterbenz
54  */
55 final class X509TrustManagerImpl extends X509ExtendedTrustManager
56         implements X509TrustManager {
57 
58     private final String validatorType;
59 
60     /**
61      * The Set of trusted X509Certificates.
62      */
63     private final Collection<X509Certificate> trustedCerts;
64 
65     private final PKIXBuilderParameters pkixParams;
66 
67     // note that we need separate validator for client and server due to
68     // the different extension checks. They are initialized lazily on demand.
69     private volatile Validator clientValidator, serverValidator;
70 
71     private static final Debug debug = Debug.getInstance("ssl");
72 
X509TrustManagerImpl(String validatorType, KeyStore ks)73     X509TrustManagerImpl(String validatorType, KeyStore ks)
74             throws KeyStoreException {
75         this.validatorType = validatorType;
76         this.pkixParams = null;
77         if (ks == null) {
78             trustedCerts = Collections.<X509Certificate>emptySet();
79         } else {
80             trustedCerts = KeyStores.getTrustedCerts(ks);
81         }
82         showTrustedCerts();
83     }
84 
X509TrustManagerImpl(String validatorType, PKIXBuilderParameters params)85     X509TrustManagerImpl(String validatorType, PKIXBuilderParameters params) {
86         this.validatorType = validatorType;
87         this.pkixParams = params;
88         // create server validator eagerly so that we can conveniently
89         // get the trusted certificates
90         // clients need it anyway eventually, and servers will not mind
91         // the little extra footprint
92         Validator v = getValidator(Validator.VAR_TLS_SERVER);
93         trustedCerts = v.getTrustedCertificates();
94         serverValidator = v;
95         showTrustedCerts();
96     }
97 
98     @Override
checkClientTrusted(X509Certificate chain[], String authType)99     public void checkClientTrusted(X509Certificate chain[], String authType)
100             throws CertificateException {
101         checkTrusted(chain, authType, (Socket)null, true);
102     }
103 
104     @Override
checkServerTrusted(X509Certificate chain[], String authType)105     public void checkServerTrusted(X509Certificate chain[], String authType)
106             throws CertificateException {
107         checkTrusted(chain, authType, (Socket)null, false);
108     }
109 
110     @Override
getAcceptedIssuers()111     public X509Certificate[] getAcceptedIssuers() {
112         X509Certificate[] certsArray = new X509Certificate[trustedCerts.size()];
113         trustedCerts.toArray(certsArray);
114         return certsArray;
115     }
116 
117     @Override
checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)118     public void checkClientTrusted(X509Certificate[] chain, String authType,
119                 Socket socket) throws CertificateException {
120         checkTrusted(chain, authType, socket, true);
121     }
122 
123     @Override
checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)124     public void checkServerTrusted(X509Certificate[] chain, String authType,
125             Socket socket) throws CertificateException {
126         checkTrusted(chain, authType, socket, false);
127     }
128 
129     @Override
checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)130     public void checkClientTrusted(X509Certificate[] chain, String authType,
131             SSLEngine engine) throws CertificateException {
132         checkTrusted(chain, authType, engine, true);
133     }
134 
135     @Override
checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)136     public void checkServerTrusted(X509Certificate[] chain, String authType,
137             SSLEngine engine) throws CertificateException {
138         checkTrusted(chain, authType, engine, false);
139     }
140 
checkTrustedInit(X509Certificate[] chain, String authType, boolean isClient)141     private Validator checkTrustedInit(X509Certificate[] chain,
142                                         String authType, boolean isClient) {
143         if (chain == null || chain.length == 0) {
144             throw new IllegalArgumentException(
145                 "null or zero-length certificate chain");
146         }
147 
148         if (authType == null || authType.length() == 0) {
149             throw new IllegalArgumentException(
150                 "null or zero-length authentication type");
151         }
152 
153         Validator v = null;
154         if (isClient) {
155             v = clientValidator;
156             if (v == null) {
157                 synchronized (this) {
158                     v = clientValidator;
159                     if (v == null) {
160                         v = getValidator(Validator.VAR_TLS_CLIENT);
161                         clientValidator = v;
162                     }
163                 }
164             }
165         } else {
166             // assume double checked locking with a volatile flag works
167             // (guaranteed under the new Tiger memory model)
168             v = serverValidator;
169             if (v == null) {
170                 synchronized (this) {
171                     v = serverValidator;
172                     if (v == null) {
173                         v = getValidator(Validator.VAR_TLS_SERVER);
174                         serverValidator = v;
175                     }
176                 }
177             }
178         }
179 
180         return v;
181     }
182 
183 
checkTrusted(X509Certificate[] chain, String authType, Socket socket, boolean isClient)184     private void checkTrusted(X509Certificate[] chain, String authType,
185                 Socket socket, boolean isClient) throws CertificateException {
186         Validator v = checkTrustedInit(chain, authType, isClient);
187 
188         AlgorithmConstraints constraints = null;
189         if ((socket != null) && socket.isConnected() &&
190                                         (socket instanceof SSLSocket)) {
191 
192             SSLSocket sslSocket = (SSLSocket)socket;
193             SSLSession session = sslSocket.getHandshakeSession();
194             if (session == null) {
195                 throw new CertificateException("No handshake session");
196             }
197 
198             // check endpoint identity
199             String identityAlg = sslSocket.getSSLParameters().
200                                         getEndpointIdentificationAlgorithm();
201             if (identityAlg != null && identityAlg.length() != 0) {
202                 String hostname = session.getPeerHost();
203                 checkIdentity(hostname, chain[0], identityAlg);
204             }
205 
206             // create the algorithm constraints
207             ProtocolVersion protocolVersion =
208                 ProtocolVersion.valueOf(session.getProtocol());
209             if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
210                 if (session instanceof ExtendedSSLSession) {
211                     ExtendedSSLSession extSession =
212                                     (ExtendedSSLSession)session;
213                     String[] localSupportedSignAlgs =
214                             extSession.getLocalSupportedSignatureAlgorithms();
215 
216                     constraints = new SSLAlgorithmConstraints(
217                                     sslSocket, localSupportedSignAlgs, false);
218                 } else {
219                     constraints =
220                             new SSLAlgorithmConstraints(sslSocket, false);
221                 }
222             } else {
223                 constraints = new SSLAlgorithmConstraints(sslSocket, false);
224             }
225         }
226 
227         X509Certificate[] trustedChain = null;
228         if (isClient) {
229             trustedChain = validate(v, chain, constraints, null);
230         } else {
231             trustedChain = validate(v, chain, constraints, authType);
232         }
233         if (debug != null && Debug.isOn("trustmanager")) {
234             System.out.println("Found trusted certificate:");
235             System.out.println(trustedChain[trustedChain.length - 1]);
236         }
237     }
238 
checkTrusted(X509Certificate[] chain, String authType, SSLEngine engine, boolean isClient)239     private void checkTrusted(X509Certificate[] chain, String authType,
240             SSLEngine engine, boolean isClient) throws CertificateException {
241         Validator v = checkTrustedInit(chain, authType, isClient);
242 
243         AlgorithmConstraints constraints = null;
244         if (engine != null) {
245             SSLSession session = engine.getHandshakeSession();
246             if (session == null) {
247                 throw new CertificateException("No handshake session");
248             }
249 
250             // check endpoint identity
251             String identityAlg = engine.getSSLParameters().
252                                         getEndpointIdentificationAlgorithm();
253             if (identityAlg != null && identityAlg.length() != 0) {
254                 String hostname = session.getPeerHost();
255                 checkIdentity(hostname, chain[0], identityAlg);
256             }
257 
258             // create the algorithm constraints
259             ProtocolVersion protocolVersion =
260                 ProtocolVersion.valueOf(session.getProtocol());
261             if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
262                 if (session instanceof ExtendedSSLSession) {
263                     ExtendedSSLSession extSession =
264                                     (ExtendedSSLSession)session;
265                     String[] localSupportedSignAlgs =
266                             extSession.getLocalSupportedSignatureAlgorithms();
267 
268                     constraints = new SSLAlgorithmConstraints(
269                                     engine, localSupportedSignAlgs, false);
270                 } else {
271                     constraints =
272                             new SSLAlgorithmConstraints(engine, false);
273                 }
274             } else {
275                 constraints = new SSLAlgorithmConstraints(engine, false);
276             }
277         }
278 
279         X509Certificate[] trustedChain = null;
280         if (isClient) {
281             trustedChain = validate(v, chain, constraints, null);
282         } else {
283             trustedChain = validate(v, chain, constraints, authType);
284         }
285         if (debug != null && Debug.isOn("trustmanager")) {
286             System.out.println("Found trusted certificate:");
287             System.out.println(trustedChain[trustedChain.length - 1]);
288         }
289     }
290 
showTrustedCerts()291     private void showTrustedCerts() {
292         if (debug != null && Debug.isOn("trustmanager")) {
293             for (X509Certificate cert : trustedCerts) {
294                 System.out.println("adding as trusted cert:");
295                 System.out.println("  Subject: "
296                                         + cert.getSubjectX500Principal());
297                 System.out.println("  Issuer:  "
298                                         + cert.getIssuerX500Principal());
299                 System.out.println("  Algorithm: "
300                                         + cert.getPublicKey().getAlgorithm()
301                                         + "; Serial number: 0x"
302                                         + cert.getSerialNumber().toString(16));
303                 System.out.println("  Valid from "
304                                         + cert.getNotBefore() + " until "
305                                         + cert.getNotAfter());
306                 System.out.println();
307             }
308         }
309     }
310 
getValidator(String variant)311     private Validator getValidator(String variant) {
312         Validator v;
313         if (pkixParams == null) {
314             v = Validator.getInstance(validatorType, variant, trustedCerts);
315         } else {
316             v = Validator.getInstance(validatorType, variant, pkixParams);
317         }
318         return v;
319     }
320 
validate(Validator v, X509Certificate[] chain, AlgorithmConstraints constraints, String authType)321     private static X509Certificate[] validate(Validator v,
322             X509Certificate[] chain, AlgorithmConstraints constraints,
323             String authType) throws CertificateException {
324         Object o = JsseJce.beginFipsProvider();
325         try {
326             return v.validate(chain, null, constraints, authType);
327         } finally {
328             JsseJce.endFipsProvider(o);
329         }
330     }
331 
332     /*
333      * Identify the peer by its certificate and hostname.
334      *
335      * Lifted from sun.net.www.protocol.https.HttpsClient.
336      */
checkIdentity(String hostname, X509Certificate cert, String algorithm)337     static void checkIdentity(String hostname, X509Certificate cert,
338             String algorithm) throws CertificateException {
339         if (algorithm != null && algorithm.length() != 0) {
340             // if IPv6 strip off the "[]"
341             if ((hostname != null) && hostname.startsWith("[") &&
342                     hostname.endsWith("]")) {
343                 hostname = hostname.substring(1, hostname.length() - 1);
344             }
345 
346             if (algorithm.equalsIgnoreCase("HTTPS")) {
347                 HostnameChecker.getInstance(HostnameChecker.TYPE_TLS).match(
348                         hostname, cert);
349             } else if (algorithm.equalsIgnoreCase("LDAP") ||
350                     algorithm.equalsIgnoreCase("LDAPS")) {
351                 HostnameChecker.getInstance(HostnameChecker.TYPE_LDAP).match(
352                         hostname, cert);
353             } else {
354                 throw new CertificateException(
355                         "Unknown identification algorithm: " + algorithm);
356             }
357         }
358     }
359 }
360