001 /*
002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.11/src/java/org/apache/commons/ssl/TrustChain.java $
003 * $Revision: 138 $
004 * $Date: 2008-03-03 23:50:07 -0800 (Mon, 03 Mar 2008) $
005 *
006 * ====================================================================
007 * Licensed to the Apache Software Foundation (ASF) under one
008 * or more contributor license agreements. See the NOTICE file
009 * distributed with this work for additional information
010 * regarding copyright ownership. The ASF licenses this file
011 * to you under the Apache License, Version 2.0 (the
012 * "License"); you may not use this file except in compliance
013 * with the License. You may obtain a copy of the License at
014 *
015 * http://www.apache.org/licenses/LICENSE-2.0
016 *
017 * Unless required by applicable law or agreed to in writing,
018 * software distributed under the License is distributed on an
019 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
020 * KIND, either express or implied. See the License for the
021 * specific language governing permissions and limitations
022 * under the License.
023 * ====================================================================
024 *
025 * This software consists of voluntary contributions made by many
026 * individuals on behalf of the Apache Software Foundation. For more
027 * information on the Apache Software Foundation, please see
028 * <http://www.apache.org/>.
029 *
030 */
031
032 package org.apache.commons.ssl;
033
034 import java.io.IOException;
035 import java.security.KeyStore;
036 import java.security.KeyStoreException;
037 import java.security.NoSuchAlgorithmException;
038 import java.security.cert.CertificateException;
039 import java.security.cert.X509Certificate;
040 import java.util.Collections;
041 import java.util.Enumeration;
042 import java.util.HashSet;
043 import java.util.Iterator;
044 import java.util.Set;
045 import java.util.SortedSet;
046 import java.util.TreeSet;
047
048 /**
049 * @author Credit Union Central of British Columbia
050 * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
051 * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
052 * @since 27-Feb-2006
053 */
054 public class TrustChain {
055 private final Set trustMaterial =
056 Collections.synchronizedSet(new HashSet());
057 private SortedSet x509Certificates = null;
058 private KeyStore unifiedKeyStore = null;
059
060 public TrustChain() {
061 }
062
063 public synchronized KeyStore getUnifiedKeyStore()
064 throws KeyStoreException, IOException, NoSuchAlgorithmException,
065 CertificateException {
066
067 // x509Certificates serves as our "cache available" indicator.
068 if (x509Certificates != null) {
069 return unifiedKeyStore;
070 }
071
072 // First, extract all the X509Certificates from this TrustChain.
073 this.x509Certificates = new TreeSet(Certificates.COMPARE_BY_EXPIRY);
074 Iterator it = trustMaterial.iterator();
075 while (it.hasNext()) {
076 TrustMaterial tm = (TrustMaterial) it.next();
077 KeyStore ks = tm.getKeyStore();
078 if (ks != null) {
079 Enumeration en = ks.aliases();
080 while (en.hasMoreElements()) {
081 String alias = (String) en.nextElement();
082 if (ks.isCertificateEntry(alias)) {
083 X509Certificate cert;
084 cert = (X509Certificate) ks.getCertificate(alias);
085 if (!x509Certificates.contains(cert)) {
086 x509Certificates.add(cert);
087 }
088 }
089 }
090 }
091 }
092
093 // Now that the X509Certificates are extracted, create the unified
094 // keystore.
095 it = x509Certificates.iterator();
096 KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
097 ks.load(null, null);
098 int count = 0;
099 while (it.hasNext()) {
100 X509Certificate cert = (X509Certificate) it.next();
101 // The "count" should keep the aliases unique (is that important?)
102 String alias = "commons-ssl-" + count;
103 ks.setCertificateEntry(alias, cert);
104 count++;
105 }
106 this.unifiedKeyStore = ks;
107 return unifiedKeyStore;
108 }
109
110 public synchronized void addTrustMaterial(TrustChain tc) {
111 this.x509Certificates = null; // invalidate cache
112 if (tc instanceof TrustMaterial) {
113 trustMaterial.add(tc);
114 }
115 // If duplicates are added, the Set will remove them.
116 trustMaterial.addAll(tc.trustMaterial);
117 }
118
119 public boolean contains(TrustChain tc) {
120 if (tc instanceof TrustMaterial) {
121 return trustMaterial.contains(tc);
122 } else {
123 return trustMaterial.containsAll(tc.trustMaterial);
124 }
125 }
126
127 public boolean contains(X509Certificate cert)
128 throws KeyStoreException, IOException, NoSuchAlgorithmException,
129 CertificateException {
130 return getCertificates().contains(cert);
131 }
132
133 public Object getTrustManagerFactory()
134 throws NoSuchAlgorithmException, KeyStoreException, IOException,
135 CertificateException {
136 KeyStore uks = getUnifiedKeyStore();
137 if (uks != null) {
138 return JavaImpl.newTrustManagerFactory(uks);
139 } else {
140 return null;
141 }
142 }
143
144 /**
145 * @return Array of TrustManager[] - presumably these will be dropped into
146 * a call to SSLContext.init(). Note: returns null if this
147 * TrustChain doesn't contain anything to trust.
148 * @throws NoSuchAlgorithmException serious problems
149 * @throws KeyStoreException serious problems
150 * @throws IOException serious problems
151 * @throws CertificateException serious problems
152 */
153 public Object[] getTrustManagers()
154 throws NoSuchAlgorithmException, KeyStoreException, IOException,
155 CertificateException {
156 Object tmf = getTrustManagerFactory();
157 return tmf != null ? JavaImpl.getTrustManagers(tmf) : null;
158 }
159
160 /**
161 * @return All X509Certificates contained in this TrustChain as a SortedSet.
162 * The X509Certificates are sorted based on expiry date.
163 * <p/>
164 * See org.apache.commons.ssl.Certificates.COMPARE_BY_EXPIRY.
165 * @throws KeyStoreException serious problems
166 * @throws IOException serious problems
167 * @throws NoSuchAlgorithmException serious problems
168 * @throws CertificateException serious problems
169 */
170 public synchronized SortedSet getCertificates()
171 throws KeyStoreException, IOException, NoSuchAlgorithmException,
172 CertificateException {
173 if (x509Certificates == null) {
174 getUnifiedKeyStore();
175 }
176 return Collections.unmodifiableSortedSet(x509Certificates);
177 }
178
179 /**
180 * @return Count of all X509Certificates contained in this TrustChain.
181 * @throws KeyStoreException
182 * @throws IOException
183 * @throws NoSuchAlgorithmException
184 * @throws CertificateException
185 */
186 public synchronized int getSize()
187 throws KeyStoreException, IOException, NoSuchAlgorithmException,
188 CertificateException {
189 return getCertificates().size();
190 }
191
192 /**
193 * @return Count of all X509Certificates contained in this TrustChain.
194 * @throws KeyStoreException
195 * @throws IOException
196 * @throws NoSuchAlgorithmException
197 * @throws CertificateException
198 */
199 public synchronized boolean isEmpty()
200 throws KeyStoreException, IOException, NoSuchAlgorithmException,
201 CertificateException {
202 return getCertificates().isEmpty();
203 }
204
205 protected boolean containsTrustAll() {
206 Iterator it = trustMaterial.iterator();
207 while (it.hasNext()) {
208 TrustChain tc = (TrustChain) it.next();
209 if (tc == this) {
210 continue;
211 }
212 if (tc.containsTrustAll()) {
213 return true;
214 }
215 }
216 return false;
217 }
218
219 }