View Javadoc

1   /* ConfigurableX509TrustManager
2    *
3    * Created on Feb 18, 2004
4    *
5    * Copyright (C) 2004 Internet Archive.
6    *
7    * This file is part of the Heritrix web crawler (crawler.archive.org).
8    *
9    * Heritrix is free software; you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser Public License as published by
11   * the Free Software Foundation; either version 2.1 of the License, or
12   * any later version.
13   *
14   * Heritrix is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU Lesser Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser Public License
20   * along with Heritrix; if not, write to the Free Software
21   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22   */
23  package org.archive.httpclient;
24  
25  import java.security.KeyStore;
26  import java.security.KeyStoreException;
27  import java.security.NoSuchAlgorithmException;
28  import java.security.cert.CertificateException;
29  import java.security.cert.X509Certificate;
30  import java.util.Arrays;
31  import java.util.List;
32  import java.util.logging.Logger;
33  
34  import javax.net.ssl.TrustManager;
35  import javax.net.ssl.TrustManagerFactory;
36  import javax.net.ssl.X509TrustManager;
37  
38  /***
39   * A configurable trust manager built on X509TrustManager.
40   *
41   * If set to 'open' trust, the default, will get us into sites for whom we do
42   * not have the CA or any of intermediary CAs that go to make up the cert chain
43   * of trust.  Will also get us past selfsigned and expired certs.  'loose'
44   * trust will get us into sites w/ valid certs even if they are just
45   * selfsigned.  'normal' is any valid cert not including selfsigned.  'strict'
46   * means cert must be valid and the cert DN must match server name.
47   *
48   * <p>Based on pointers in
49   * <a href="http://jakarta.apache.org/commons/httpclient/sslguide.html">SSL
50   * Guide</a>,
51   * and readings done in <a
52   * href="http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html#Introduction">JSSE
53   * Guide</a>.
54   *
55   * <p>TODO: Move to an ssl subpackage when we have other classes other than
56   * just this one.
57   *
58   * @author stack
59   * @version $Id: ConfigurableX509TrustManager.java 4232 2006-05-15 21:52:30Z stack-sf $
60   */
61  public class ConfigurableX509TrustManager implements X509TrustManager
62  {
63      /***
64       * Logging instance.
65       */
66      protected static Logger logger = Logger.getLogger(
67          "org.archive.httpclient.ConfigurableX509TrustManager");
68  
69      /***
70       * Trust anything given us.
71       *
72       * Default setting.
73       *
74       * <p>See <a href="http://javaalmanac.com/egs/javax.net.ssl/TrustAll.html">
75       *  e502. Disabling Certificate Validation in an HTTPS Connection</a> from
76       * the java almanac for how to trust all.
77       */
78      public final static String OPEN = "open";
79  
80      /***
81       * Trust any valid cert including self-signed certificates.
82       */
83      public final static String LOOSE = "loose";
84  
85      /***
86       * Normal jsse behavior.
87       *
88       * Seemingly any certificate that supplies valid chain of trust.
89       */
90      public final static String NORMAL = "normal";
91  
92      /***
93       * Strict trust.
94       *
95       * Ensure server has same name as cert DN.
96       */
97      public final static String STRICT = "strict";
98  
99      /***
100      * All the levels of trust as an array from babe-in-the-wood to strict.
101      */
102     public static String [] LEVELS_AS_ARRAY = {OPEN, LOOSE, NORMAL, STRICT};
103 
104     /***
105      * Levels as a list.
106      */
107     private static List LEVELS = Arrays.asList(LEVELS_AS_ARRAY);
108 
109     /***
110      * Default setting for trust level.
111      */
112     public final static String DEFAULT = OPEN;
113 
114     /***
115      * Trust level.
116      */
117     private String trustLevel = DEFAULT;
118 
119 
120     /***
121      * An instance of the SUNX509TrustManager that we adapt variously
122      * depending upon passed configuration.
123      *
124      * We have it do all the work we don't want to.
125      */
126     private X509TrustManager standardTrustManager = null;
127 
128 
129     public ConfigurableX509TrustManager()
130     throws NoSuchAlgorithmException, KeyStoreException {
131         this(DEFAULT);
132     }
133 
134     /***
135      * Constructor.
136      *
137      * @param level Level of trust to effect.
138      *
139      * @throws NoSuchAlgorithmException
140      * @throws KeyStoreException
141      */
142     public ConfigurableX509TrustManager(String level)
143     throws NoSuchAlgorithmException, KeyStoreException {
144         super();
145         TrustManagerFactory factory = TrustManagerFactory.
146             getInstance(TrustManagerFactory.getDefaultAlgorithm());
147 
148         // Pass in a null (Trust) KeyStore.  Null says use the 'default'
149         // 'trust' keystore (KeyStore class is used to hold keys and to hold
150         // 'trusts' (certs)). See 'X509TrustManager Interface' in this doc:
151         // http://java.sun.com
152         // /j2se/1.4.2/docs/guide/security/jsse/JSSERefGuide.html#Introduction
153         factory.init((KeyStore)null);
154         TrustManager[] trustmanagers = factory.getTrustManagers();
155         if (trustmanagers.length == 0) {
156             throw new NoSuchAlgorithmException(TrustManagerFactory.
157                 getDefaultAlgorithm() + " trust manager not supported");
158         }
159         this.standardTrustManager = (X509TrustManager)trustmanagers[0];
160 
161         this.trustLevel =
162             (LEVELS.contains(level.toLowerCase()))? level: DEFAULT;
163     }
164 
165     public void checkClientTrusted(X509Certificate[] certificates, String type)
166     throws CertificateException {
167         if (this.trustLevel.equals(OPEN)) {
168             return;
169         }
170 
171         this.standardTrustManager.checkClientTrusted(certificates, type);
172     }
173 
174     public void checkServerTrusted(X509Certificate[] certificates, String type)
175     throws CertificateException {
176         if (this.trustLevel.equals(OPEN)) {
177             return;
178         }
179 
180         try {
181             this.standardTrustManager.checkServerTrusted(certificates, type);
182             if (this.trustLevel.equals(STRICT)) {
183                 logger.severe(STRICT + " not implemented.");
184             }
185         } catch (CertificateException e) {
186             if (this.trustLevel.equals(LOOSE) &&
187                 certificates != null && certificates.length == 1)
188             {
189                     // If only one cert and its valid and it caused a
190                     // CertificateException, assume its selfsigned.
191                     X509Certificate certificate = certificates[0];
192                     certificate.checkValidity();
193             } else {
194                 // If we got to here, then we're probably NORMAL. Rethrow.
195                 throw e;
196             }
197         }
198     }
199 
200     public X509Certificate[] getAcceptedIssuers() {
201         return this.standardTrustManager.getAcceptedIssuers();
202     }
203 }