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 }