001/* 002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.16/src/java/org/apache/commons/ssl/TrustMaterial.java $ 003 * $Revision: 171 $ 004 * $Date: 2014-05-09 08:15:26 -0700 (Fri, 09 May 2014) $ 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.Certificate; 043import java.security.cert.X509Certificate; 044import java.util.Arrays; 045import java.util.Collection; 046import java.util.Collections; 047import java.util.Enumeration; 048import 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 */ 056public 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 public TrustMaterial(byte[] jks, char[] password) 209 throws GeneralSecurityException, IOException { 210 211 KeyStoreBuilder.BuildResult br; 212 br = KeyStoreBuilder.parse(jks, password, null, true); 213 if (br.jks != null) { 214 // If we've been given a keystore, just use that. 215 this.jks = br.jks; 216 } else { 217 // Otherwise we need to build a keystore from what we were given. 218 KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); 219 if (br.chains != null && !br.chains.isEmpty()) { 220 Certificate[] c = (Certificate[]) br.chains.get(0); 221 if (c.length > 0) { 222 ks.load(null, password); 223 loadCerts(ks, Arrays.asList(c)); 224 } 225 } 226 this.jks = ks; 227 } 228 229 // Should validate our keystore to make sure it has at least ONE 230 // certificate entry: 231 KeyStore ks = this.jks; 232 boolean hasCertificates = false; 233 Enumeration en = ks.aliases(); 234 while (en.hasMoreElements()) { 235 String alias = (String) en.nextElement(); 236 if (ks.isCertificateEntry(alias)) { 237 hasCertificates = true; 238 break; 239 } 240 } 241 if (!hasCertificates) { 242 throw new KeyStoreException("TrustMaterial couldn't load any certificates to trust!"); 243 } 244 245 addTrustMaterial(this); 246 247 // We're not a simple trust type, so set value to 0. 248 // Only TRUST_ALL and TRUST_THIS_JVM are simple trust types. 249 this.simpleTrustType = 0; 250 } 251 252 public KeyStore getKeyStore() { 253 return jks; 254 } 255 256 private static void loadCerts(KeyStore ks, Collection certs) 257 throws KeyStoreException { 258 Iterator it = certs.iterator(); 259 int count = 0; 260 while (it.hasNext()) { 261 X509Certificate cert = (X509Certificate) it.next(); 262 263 // I could be fancy and parse out the CN field from the 264 // certificate's subject, but these names don't actually matter 265 // at all - I think they just have to be unique. 266 String cn = Certificates.getCN(cert); 267 String alias = cn + "_" + count; 268 ks.setCertificateEntry(alias, cert); 269 count++; 270 } 271 } 272 273 protected boolean containsTrustAll() { 274 boolean yes = this.simpleTrustType == SIMPLE_TRUST_TYPE_TRUST_ALL; 275 if ( !yes ) { 276 yes = super.containsTrustAll(); 277 } 278 return yes; 279 } 280 281}