Java tutorial
/* * $Id: ExtendedX509TrustManager.java,v 1.6 2007/03/01 13:46:29 vtschopp Exp $ * * Created on Aug 8, 2006 by tschopp * * Copyright (c) Members of the EGEE Collaboration. 2004. * See http://eu-egee.org/partners/ for details on the copyright holders. * For license conditions see the license file or http://eu-egee.org/license.html */ package org.glite.slcs.httpclient.ssl; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import javax.net.ssl.X509TrustManager; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * ExtendedTrustX509TrustManager can be used to extend the default JSSE * {@link X509TrustManager} with additional trusted CAs stored in a trust store. * * @author Valery Tschoppp <tschopp@switch.ch> * @version $Revision: 1.6 $ */ public class ExtendedX509TrustManager implements X509TrustManager { /** The default JSSE TrustManager used as delegate */ private X509TrustManager defaultTrustManager_ = null; /** * List of trusted X509Certificate (trusted CA). */ private List trustedIssuers_ = null; /** Log object for this class. */ private static final Log LOG = LogFactory.getLog(ExtendedX509TrustManager.class); /** * Constructor for ExtendedX509TrustManager. * * @param truststore * The trust KeyStore containing the additional trusted CA. * @param defaultTrustManager * The default JSSE X509TrustManager * @throws KeyStoreException */ public ExtendedX509TrustManager(KeyStore trustStore, X509TrustManager defaultTrustManager) throws KeyStoreException { super(); if (trustStore == null) { throw new IllegalArgumentException("Trust KeyStore may not be null"); } if (defaultTrustManager == null) { throw new IllegalArgumentException("Default X509TrustManager may not be null"); } defaultTrustManager_ = defaultTrustManager; trustedIssuers_ = createTrustedIssuers(trustStore); if (LOG.isDebugEnabled()) { // dumpTrustStore(trustStore); dumpTrustedIssuers(trustedIssuers_); } } static protected List createTrustedIssuers(KeyStore truststore) throws KeyStoreException { List trustedcerts = new ArrayList(); Enumeration aliases = truststore.aliases(); while (aliases.hasMoreElements()) { String alias = (String) aliases.nextElement(); Certificate trustedcert = truststore.getCertificate(alias); if (trustedcert != null && trustedcert instanceof X509Certificate) { X509Certificate cert = (X509Certificate) trustedcert; trustedcerts.add(cert); } } return trustedcerts; } static private void dumpTrustedIssuers(List trustedIssuers) { LOG.debug("Trusted Issuers:"); Iterator certs = trustedIssuers.iterator(); while (certs.hasNext()) { X509Certificate cert = (X509Certificate) certs.next(); dumpCertificate(cert); } } static private void dumpCertificate(X509Certificate cert) { LOG.debug("Certificate:"); LOG.debug(" Subject: " + cert.getSubjectDN()); LOG.debug(" Issuer: " + cert.getIssuerDN()); LOG.debug(" Valid from: " + cert.getNotBefore()); LOG.debug(" Valid until: " + cert.getNotAfter()); LOG.debug(" Fingerprint: " + getCertificateFingerprint(cert, "MD5")); } static private String getCertificateFingerprint(X509Certificate certificate, String algorithm) { byte[] digest = null; try { byte[] certificateBytes = certificate.getEncoded(); MessageDigest md = MessageDigest.getInstance(algorithm); md.update(certificateBytes); digest = md.digest(); } catch (CertificateEncodingException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return new String(algorithm + ": " + byteArrayToHex(digest)); } static private String byteArrayToHex(byte[] byteData) { if (byteData == null) { return ""; } StringBuffer sb = new StringBuffer(); for (int i = 0; i < byteData.length; i++) { if (i != 0) sb.append(":"); int b = byteData[i] & 0xff; String hex = Integer.toHexString(b); if (hex.length() == 1) sb.append("0"); sb.append(hex); } return sb.toString().toUpperCase(); } /** * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String * authType) */ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { // use delegate for client certificates if (LOG.isDebugEnabled()) { LOG.debug("Certificate chain:"); if (chain != null) { for (int i = 0; i < chain.length; i++) { X509Certificate certificate = chain[i]; LOG.debug(i + ": S: " + certificate.getSubjectX500Principal()); LOG.debug(i + ": I: " + certificate.getIssuerX500Principal()); } } } defaultTrustManager_.checkClientTrusted(chain, authType); } /** * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String * authType) */ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { if (LOG.isDebugEnabled()) { LOG.debug("Certificate chain:"); if (chain != null) { for (int i = 0; i < chain.length; i++) { X509Certificate certificate = chain[i]; LOG.debug(i + ": S: " + certificate.getSubjectDN()); LOG.debug(i + ": I: " + certificate.getIssuerDN()); } } } try { // delegate to default JSSE TrustManager defaultTrustManager_.checkServerTrusted(chain, authType); } catch (CertificateException ce) { LOG.debug("Extended checking of certificate chain"); // Start with the root and see if the subject or the issuer is // in the trustedIssuers HashTable. // The root is at the end of the chain. boolean trusted = false; for (int i = chain.length - 1; i >= 0; i--) { X509Certificate cert = chain[i]; if (isCertificateIssuerTrusted(cert)) { LOG.debug("Trusted X509 Issuer: " + cert.getIssuerDN()); trusted = true; break; } else if (isCertificateTrusted(cert)) { LOG.debug("Trusted X509 Certificate: " + cert.getSubjectDN()); trusted = true; break; } } if (!trusted) { LOG.error("No suitable trusted certificate found in truststore: ", ce); throw ce; } } } /** * Checks if the certificate is store in our trust store. * * @param cert * The X509 certificate to check. * @return <code>true</code> if the certificate is in trustedIssuers * hashtable as value. */ protected boolean isCertificateTrusted(X509Certificate cert) { return trustedIssuers_.contains(cert); } /** * Returns <code>true</code> iff the certificate issuer is in our trust * store and it have signed the cert. * * @param cert * The X509 certificate to check. * @return <code>true</code> if the certificate issuer is in * trustedIssuers list and have signed the cert. */ protected boolean isCertificateIssuerTrusted(X509Certificate cert) { //TODO: checks CA CRL // checks if an trusted issuer have signed the certificate boolean trusted = false; Iterator issuers = trustedIssuers_.iterator(); while (issuers.hasNext()) { X509Certificate issuer = (X509Certificate) issuers.next(); PublicKey issuerPublicKey = issuer.getPublicKey(); try { if (LOG.isDebugEnabled()) { LOG.debug("checking: " + issuer.getSubjectDN()); } cert.verify(issuerPublicKey); trusted = true; break; } catch (GeneralSecurityException e) { if (LOG.isDebugEnabled()) { LOG.debug(e); } } } if (!trusted) { LOG.warn("No trusted issuer found in TrustStore for: " + cert.getSubjectDN()); } return trusted; } /** * Merges the system wide accepted issuers and the own ones and returns * them. * * @return Array of X509 certificates of the accepted issuers. * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers() */ public X509Certificate[] getAcceptedIssuers() { X509Certificate[] defaultAcceptedIssuers = defaultTrustManager_.getAcceptedIssuers(); // merge JSSE default and trusted CA from truststore int length = trustedIssuers_.size() + defaultAcceptedIssuers.length; X509Certificate[] allAcceptedIssuers = new X509Certificate[length]; int i = 0; for (int j = 0; j < defaultAcceptedIssuers.length; j++) { X509Certificate certificate = defaultAcceptedIssuers[j]; allAcceptedIssuers[i] = certificate; i++; } Iterator trustedCerts = trustedIssuers_.iterator(); while (trustedCerts.hasNext()) { X509Certificate certificate = (X509Certificate) trustedCerts.next(); allAcceptedIssuers[i] = certificate; i++; } return allAcceptedIssuers; } }