001 /*
002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.11/src/java/org/apache/commons/ssl/TrustMaterial.java $
003 * $Revision: 148 $
004 * $Date: 2009-05-25 23:07:21 -0700 (Mon, 25 May 2009) $
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.File;
035 import java.io.FileInputStream;
036 import java.io.IOException;
037 import java.io.InputStream;
038 import java.net.URL;
039 import java.security.GeneralSecurityException;
040 import java.security.KeyStore;
041 import java.security.KeyStoreException;
042 import java.security.cert.Certificate;
043 import java.security.cert.X509Certificate;
044 import java.util.Arrays;
045 import java.util.Collection;
046 import java.util.Collections;
047 import java.util.Enumeration;
048 import java.util.Iterator;
049
050 /**
051 * @author Credit Union Central of British Columbia
052 * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
053 * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
054 * @since 27-Feb-2006
055 */
056 public class TrustMaterial extends TrustChain {
057 final static int SIMPLE_TRUST_TYPE_TRUST_ALL = 1;
058 final static int SIMPLE_TRUST_TYPE_TRUST_THIS_JVM = 2;
059
060 /**
061 * Might be null if "$JAVA_HOME/jre/lib/security/cacerts" doesn't exist.
062 */
063 public final static TrustMaterial CACERTS;
064
065 /**
066 * Might be null if "$JAVA_HOME/jre/lib/security/jssecacerts" doesn't exist.
067 */
068 public final static TrustMaterial JSSE_CACERTS;
069
070 /**
071 * Should never be null (unless both CACERTS and JSSE_CACERTS are not
072 * present???). Is either CACERTS or JSSE_CACERTS. Priority given to
073 * JSSE_CACERTS, but 99.9% of the time it's CACERTS, since JSSE_CACERTS
074 * is almost never present.
075 */
076 public final static TrustMaterial DEFAULT;
077
078 static {
079 JavaImpl.load();
080 String javaHome = System.getProperty("java.home");
081 String pathToCacerts = javaHome + "/lib/security/cacerts";
082 String pathToJSSECacerts = javaHome + "/lib/security/jssecacerts";
083 TrustMaterial cacerts = null;
084 TrustMaterial jssecacerts = null;
085 try {
086 File f = new File(pathToCacerts);
087 if (f.exists()) {
088 cacerts = new TrustMaterial(pathToCacerts);
089 }
090 }
091 catch (Exception e) {
092 e.printStackTrace();
093 }
094 try {
095 File f = new File(pathToJSSECacerts);
096 if (f.exists()) {
097 jssecacerts = new TrustMaterial(pathToJSSECacerts);
098 }
099 }
100 catch (Exception e) {
101 e.printStackTrace();
102 }
103
104 CACERTS = cacerts;
105 JSSE_CACERTS = jssecacerts;
106 if (JSSE_CACERTS != null) {
107 DEFAULT = JSSE_CACERTS;
108 } else {
109 DEFAULT = CACERTS;
110 }
111 }
112
113 public final static TrustMaterial TRUST_ALL =
114 new TrustMaterial(SIMPLE_TRUST_TYPE_TRUST_ALL);
115
116 public final static TrustMaterial TRUST_THIS_JVM =
117 new TrustMaterial(SIMPLE_TRUST_TYPE_TRUST_THIS_JVM);
118
119 public final int simpleTrustType;
120 private final KeyStore jks;
121
122 private TrustMaterial(int simpleTrustType) {
123 this(null, simpleTrustType);
124 }
125
126 TrustMaterial(KeyStore jks, int simpleTrustType) {
127 if (jks == null && simpleTrustType != 0) {
128 // Just use CACERTS as a place holder, since Java 5 and 6 seem to get
129 // upset when we hand SSLContext null TrustManagers. See
130 // Java14.initSSL(), which despite its name, is also used
131 // with Java5 and Java6.
132 this.jks = CACERTS != null ? CACERTS.jks : JSSE_CACERTS.jks;
133 } else {
134 this.jks = jks;
135 }
136 addTrustMaterial(this);
137 this.simpleTrustType = simpleTrustType;
138 }
139
140 public TrustMaterial(Collection x509Certs)
141 throws GeneralSecurityException, IOException {
142 KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
143 ks.load(null, null);
144 loadCerts(ks, x509Certs);
145 this.jks = ks;
146 addTrustMaterial(this);
147
148 // We're not a simple trust type, so set value to 0.
149 // Only TRUST_ALL and TRUST_THIS_JVM are simple trust types.
150 this.simpleTrustType = 0;
151 }
152
153 public TrustMaterial(X509Certificate x509Cert)
154 throws GeneralSecurityException, IOException {
155 this(Collections.singleton(x509Cert));
156 }
157
158 public TrustMaterial(X509Certificate[] x509Certs)
159 throws GeneralSecurityException, IOException {
160 this(Arrays.asList(x509Certs));
161 }
162
163 public TrustMaterial(byte[] pemBase64)
164 throws GeneralSecurityException, IOException {
165 this(pemBase64, null);
166 }
167
168 public TrustMaterial(InputStream pemBase64)
169 throws GeneralSecurityException, IOException {
170 this(Util.streamToBytes(pemBase64));
171 }
172
173 public TrustMaterial(String pathToPemFile)
174 throws GeneralSecurityException, IOException {
175 this(new FileInputStream(pathToPemFile));
176 }
177
178 public TrustMaterial(File pemFile)
179 throws GeneralSecurityException, IOException {
180 this(new FileInputStream(pemFile));
181 }
182
183 public TrustMaterial(URL urlToPemFile)
184 throws GeneralSecurityException, IOException {
185 this(urlToPemFile.openStream());
186 }
187
188 public TrustMaterial(String pathToJksFile, char[] password)
189 throws GeneralSecurityException, IOException {
190 this(new File(pathToJksFile), password);
191 }
192
193 public TrustMaterial(File jksFile, char[] password)
194 throws GeneralSecurityException, IOException {
195 this(new FileInputStream(jksFile), password);
196 }
197
198 public TrustMaterial(URL urlToJKS, char[] password)
199 throws GeneralSecurityException, IOException {
200 this(urlToJKS.openStream(), password);
201 }
202
203 public TrustMaterial(InputStream jks, char[] password)
204 throws GeneralSecurityException, IOException {
205 this(Util.streamToBytes(jks), password);
206 }
207
208
209 public TrustMaterial(byte[] jks, char[] password)
210 throws GeneralSecurityException, IOException {
211
212 KeyStoreBuilder.BuildResult br;
213 br = KeyStoreBuilder.parse(jks, password, null);
214 if (br.jks != null) {
215 // If we've been given a keystore, just use that.
216 this.jks = br.jks;
217 } else {
218 // Otherwise we need to build a keystore from what we were given.
219 KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
220 if (br.chains != null && !br.chains.isEmpty()) {
221 Certificate[] c = (Certificate[]) br.chains.get(0);
222 if (c.length > 0) {
223 ks.load(null, password);
224 loadCerts(ks, Arrays.asList(c));
225 }
226 }
227 this.jks = ks;
228 }
229
230 // Should validate our keystore to make sure it has at least ONE
231 // certificate entry:
232 KeyStore ks = this.jks;
233 boolean hasCertificates = false;
234 Enumeration en = ks.aliases();
235 while (en.hasMoreElements()) {
236 String alias = (String) en.nextElement();
237 if (ks.isCertificateEntry(alias)) {
238 hasCertificates = true;
239 break;
240 }
241 }
242 if (!hasCertificates) {
243 throw new KeyStoreException("TrustMaterial couldn't load any certificates to trust!");
244 }
245
246 addTrustMaterial(this);
247
248 // We're not a simple trust type, so set value to 0.
249 // Only TRUST_ALL and TRUST_THIS_JVM are simple trust types.
250 this.simpleTrustType = 0;
251 }
252
253 public KeyStore getKeyStore() {
254 return jks;
255 }
256
257 private static void loadCerts(KeyStore ks, Collection certs)
258 throws KeyStoreException {
259 Iterator it = certs.iterator();
260 int count = 0;
261 while (it.hasNext()) {
262 X509Certificate cert = (X509Certificate) it.next();
263
264 // I could be fancy and parse out the CN field from the
265 // certificate's subject, but these names don't actually matter
266 // at all - I think they just have to be unique.
267 String cn = Certificates.getCN(cert);
268 String alias = cn + "_" + count;
269 ks.setCertificateEntry(alias, cert);
270 count++;
271 }
272 }
273
274 protected boolean containsTrustAll() {
275 boolean yes = this.simpleTrustType == SIMPLE_TRUST_TYPE_TRUST_ALL;
276 if ( !yes ) {
277 yes = super.containsTrustAll();
278 }
279 return yes;
280 }
281
282 }