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 }