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