001: /*
002: * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.security.ssl;
027:
028: import java.util.*;
029: import java.security.*;
030: import java.security.cert.*;
031:
032: import javax.net.ssl.*;
033:
034: import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager;
035:
036: import sun.security.validator.*;
037:
038: import sun.security.util.HostnameChecker;
039:
040: /**
041: * This class implements the SunJSSE X.509 trust manager using the internal
042: * validator API in J2SE core. The logic in this class is minimal.<p>
043: *
044: * This class supports both the Simple validation algorithm from previous
045: * JSSE versions and PKIX validation. Currently, it is not possible for the
046: * application to specify PKIX parameters other than trust anchors. This will
047: * be fixed in a future release using new APIs. When that happens, it may also
048: * make sense to separate the Simple and PKIX trust managers into separate
049: * classes.
050: *
051: * @version 1.60, 05/05/07
052: * @author Andreas Sterbenz
053: * @author Xuelei Fan
054: */
055: final class X509TrustManagerImpl extends X509ExtendedTrustManager
056: implements X509TrustManager {
057:
058: /**
059: * Flag indicating whether to enable revocation check for the PKIX trust
060: * manager. Typically, this will only work if the PKIX implementation
061: * supports CRL distribution points as we do not manually setup CertStores.
062: */
063: private final static boolean checkRevocation = Debug
064: .getBooleanProperty("com.sun.net.ssl.checkRevocation",
065: false);
066:
067: private final String validatorType;
068:
069: /**
070: * The Set of trusted X509Certificates.
071: */
072: private final Collection<X509Certificate> trustedCerts;
073:
074: private final PKIXBuilderParameters pkixParams;
075:
076: // note that we need separate validator for client and server due to
077: // the different extension checks. They are initialized lazily on demand.
078: private volatile Validator clientValidator, serverValidator;
079:
080: private static final Debug debug = Debug.getInstance("ssl");
081:
082: X509TrustManagerImpl(String validatorType, KeyStore ks)
083: throws KeyStoreException {
084: this .validatorType = validatorType;
085: this .pkixParams = null;
086: if (ks == null) {
087: trustedCerts = Collections.<X509Certificate> emptySet();
088: } else {
089: trustedCerts = KeyStores.getTrustedCerts(ks);
090: }
091: showTrustedCerts();
092: }
093:
094: X509TrustManagerImpl(String validatorType,
095: PKIXBuilderParameters params) {
096: this .validatorType = validatorType;
097: this .pkixParams = params;
098: // create server validator eagerly so that we can conveniently
099: // get the trusted certificates
100: // clients need it anyway eventually, and servers will not mind
101: // the little extra footprint
102: Validator v = getValidator(Validator.VAR_TLS_SERVER);
103: trustedCerts = v.getTrustedCertificates();
104: serverValidator = v;
105: showTrustedCerts();
106: }
107:
108: private void showTrustedCerts() {
109: if (debug != null && Debug.isOn("trustmanager")) {
110: for (X509Certificate cert : trustedCerts) {
111: System.out.println("adding as trusted cert:");
112: System.out.println(" Subject: "
113: + cert.getSubjectX500Principal());
114: System.out.println(" Issuer: "
115: + cert.getIssuerX500Principal());
116: System.out.println(" Algorithm: "
117: + cert.getPublicKey().getAlgorithm()
118: + "; Serial number: 0x"
119: + cert.getSerialNumber().toString(16));
120: System.out.println(" Valid from "
121: + cert.getNotBefore() + " until "
122: + cert.getNotAfter());
123: System.out.println();
124: }
125: }
126: }
127:
128: private Validator getValidator(String variant) {
129: Validator v;
130: if (pkixParams == null) {
131: v = Validator.getInstance(validatorType, variant,
132: trustedCerts);
133: // if the PKIX validator is created from a KeyStore,
134: // disable revocation checking
135: if (v instanceof PKIXValidator) {
136: PKIXValidator pkixValidator = (PKIXValidator) v;
137: pkixValidator.getParameters().setRevocationEnabled(
138: checkRevocation);
139: }
140: } else {
141: v = Validator.getInstance(validatorType, variant,
142: pkixParams);
143: }
144: return v;
145: }
146:
147: private static X509Certificate[] validate(Validator v,
148: X509Certificate[] chain, String authType)
149: throws CertificateException {
150: Object o = JsseJce.beginFipsProvider();
151: try {
152: return v.validate(chain, null, authType);
153: } finally {
154: JsseJce.endFipsProvider(o);
155: }
156: }
157:
158: /**
159: * Returns true if the client certificate can be trusted.
160: *
161: * @param chain certificates which establish an identity for the client.
162: * Chains of arbitrary length are supported, and certificates
163: * marked internally as trusted will short-circuit signature checks.
164: * @throws IllegalArgumentException if null or zero-length chain
165: * is passed in for the chain parameter or if null or zero-length
166: * string is passed in for the authType parameter.
167: * @throws CertificateException if the certificate chain is not trusted
168: * by this TrustManager.
169: */
170: public void checkClientTrusted(X509Certificate chain[],
171: String authType) throws CertificateException {
172: if (chain == null || chain.length == 0) {
173: throw new IllegalArgumentException(
174: "null or zero-length certificate chain");
175: }
176: if (authType == null || authType.length() == 0) {
177: throw new IllegalArgumentException(
178: "null or zero-length authentication type");
179: }
180:
181: // assume double checked locking with a volatile flag works
182: // (guaranteed under the new Tiger memory model)
183: Validator v = clientValidator;
184: if (v == null) {
185: synchronized (this ) {
186: v = clientValidator;
187: if (v == null) {
188: v = getValidator(Validator.VAR_TLS_CLIENT);
189: clientValidator = v;
190: }
191: }
192: }
193: X509Certificate[] trustedChain = validate(v, chain, null);
194: if (debug != null && Debug.isOn("trustmanager")) {
195: System.out.println("Found trusted certificate:");
196: System.out.println(trustedChain[trustedChain.length - 1]);
197: }
198: }
199:
200: /**
201: * Returns true if the server certifcate can be trusted.
202: *
203: * @param chain certificates which establish an identity for the server.
204: * Chains of arbitrary length are supported, and certificates
205: * marked internally as trusted will short-circuit signature checks.
206: * @throws IllegalArgumentException if null or zero-length chain
207: * is passed in for the chain parameter or if null or zero-length
208: * string is passed in for the authType parameter.
209: * @throws CertificateException if the certificate chain is not trusted
210: * by this TrustManager.
211: */
212: public void checkServerTrusted(X509Certificate chain[],
213: String authType) throws CertificateException {
214: if (chain == null || chain.length == 0) {
215: throw new IllegalArgumentException(
216: "null or zero-length certificate chain");
217: }
218: if (authType == null || authType.length() == 0) {
219: throw new IllegalArgumentException(
220: "null or zero-length authentication type");
221: }
222:
223: // assume double checked locking with a volatile flag works
224: // (guaranteed under the new Tiger memory model)
225: Validator v = serverValidator;
226: if (v == null) {
227: synchronized (this ) {
228: v = serverValidator;
229: if (v == null) {
230: v = getValidator(Validator.VAR_TLS_SERVER);
231: serverValidator = v;
232: }
233: }
234: }
235: X509Certificate[] trustedChain = validate(v, chain, authType);
236: if (debug != null && Debug.isOn("trustmanager")) {
237: System.out.println("Found trusted certificate:");
238: System.out.println(trustedChain[trustedChain.length - 1]);
239: }
240: }
241:
242: /**
243: * Returns a list of CAs accepted to authenticate entities for the
244: * specified purpose.
245: *
246: * @param purpose activity for which CAs should be trusted
247: * @return list of CAs accepted for authenticating such tasks
248: */
249: public X509Certificate[] getAcceptedIssuers() {
250: X509Certificate[] certsArray = new X509Certificate[trustedCerts
251: .size()];
252: trustedCerts.toArray(certsArray);
253: return certsArray;
254: }
255:
256: /**
257: * Given the partial or complete certificate chain provided by the
258: * peer, check its identity and build a certificate path to a trusted
259: * root, return if it can be validated and is trusted for client SSL
260: * authentication based on the authentication type.
261: */
262: public void checkClientTrusted(X509Certificate[] chain,
263: String authType, String hostname, String algorithm)
264: throws CertificateException {
265: checkClientTrusted(chain, authType);
266: checkIdentity(hostname, chain[0], algorithm);
267: }
268:
269: /**
270: * Given the partial or complete certificate chain provided by the
271: * peer, check its identity and build a certificate path to a trusted
272: * root, return if it can be validated and is trusted for server SSL
273: * authentication based on the authentication type.
274: */
275: public void checkServerTrusted(X509Certificate[] chain,
276: String authType, String hostname, String algorithm)
277: throws CertificateException {
278: checkServerTrusted(chain, authType);
279: checkIdentity(hostname, chain[0], algorithm);
280: }
281:
282: // Identify the peer by its certificate and hostname.
283: private void checkIdentity(String hostname, X509Certificate cert,
284: String algorithm) throws CertificateException {
285: if (algorithm != null && algorithm.length() != 0) {
286: // if IPv6 strip off the "[]"
287: if (hostname != null && hostname.startsWith("[")
288: && hostname.endsWith("]")) {
289: hostname = hostname.substring(1, hostname.length() - 1);
290: }
291:
292: if (algorithm.equalsIgnoreCase("HTTPS")) {
293: HostnameChecker.getInstance(HostnameChecker.TYPE_TLS)
294: .match(hostname, cert);
295: } else if (algorithm.equalsIgnoreCase("LDAP")) {
296: HostnameChecker.getInstance(HostnameChecker.TYPE_LDAP)
297: .match(hostname, cert);
298: } else {
299: throw new CertificateException(
300: "Unknown identification algorithm: "
301: + algorithm);
302: }
303: }
304: }
305: }
|