1 2 3 /* 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 5 * 6 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. 7 * 8 * Portions Copyright Apache Software Foundation. 9 * 10 * The contents of this file are subject to the terms of either the GNU 11 * General Public License Version 2 only ("GPL") or the Common Development 12 * and Distribution License("CDDL") (collectively, the "License"). You 13 * may not use this file except in compliance with the License. You can obtain 14 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html 15 * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific 16 * language governing permissions and limitations under the License. 17 * 18 * When distributing the software, include this License Header Notice in each 19 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt. 20 * Sun designates this particular file as subject to the "Classpath" exception 21 * as provided by Sun in the GPL Version 2 section of the License file that 22 * accompanied this code. If applicable, add the following below the License 23 * Header, with the fields enclosed by brackets [] replaced by your own 24 * identifying information: "Portions Copyrighted [year] 25 * [name of copyright owner]" 26 * 27 * Contributor(s): 28 * 29 * If you wish your version of this file to be governed by only the CDDL or 30 * only the GPL Version 2, indicate your decision by adding "[Contributor] 31 * elects to include this software in this distribution under the [CDDL or GPL 32 * Version 2] license." If you don't indicate a single choice of license, a 33 * recipient has the option to distribute your version of this file under 34 * either the CDDL, the GPL Version 2 or to extend the choice of license to 35 * its licensees as provided above. However, if you add GPL Version 2 code 36 * and therefore, elected the GPL Version 2 license, then the option applies 37 * only if the new code is made subject to such option by the copyright 38 * holder. 39 */ 40 41 package org.apache.tomcat.util.net.jsse; 42 43 import java.io; 44 import java.net; 45 import java.util.Collection; 46 import java.util.Vector; 47 import java.security.KeyStore; 48 import java.security.SecureRandom; 49 import java.security.cert.CRL; 50 import java.security.cert.CRLException; 51 import java.security.cert.CertPathParameters; 52 import java.security.cert.CertStore; 53 import java.security.cert.CertStoreParameters; 54 import java.security.cert.CertificateException; 55 import java.security.cert.CertificateFactory; 56 import java.security.cert.CollectionCertStoreParameters; 57 import java.security.cert.PKIXBuilderParameters; 58 import java.security.cert.X509CertSelector; 59 import javax.net.ssl.CertPathTrustManagerParameters; 60 import javax.net.ssl.SSLServerSocket; 61 import javax.net.ssl.SSLContext; 62 import javax.net.ssl.SSLSessionContext; 63 import javax.net.ssl.KeyManager; 64 import javax.net.ssl.KeyManagerFactory; 65 import javax.net.ssl.ManagerFactoryParameters; 66 import javax.net.ssl.X509KeyManager; 67 import javax.net.ssl.TrustManager; 68 import javax.net.ssl.TrustManagerFactory; 69 70 import org.apache.tomcat.util.res.StringManager; 71 72 /* 73 1. Make the JSSE's jars available, either as an installed 74 extension (copy them into jre/lib/ext) or by adding 75 them to the Tomcat classpath. 76 2. keytool -genkey -alias tomcat -keyalg RSA 77 Use "changeit" as password ( this is the default we use ) 78 */ 79 80 /** 81 * SSL server socket factory. It _requires_ a valid RSA key and 82 * JSSE. 83 * 84 * @author Harish Prabandham 85 * @author Costin Manolache 86 * @author Stefan Freyr Stefansson 87 * @author EKR -- renamed to JSSESocketFactory 88 * @author Jan Luehe 89 */ 90 public class JSSE14SocketFactory extends JSSESocketFactory { 91 92 private static StringManager sm = 93 StringManager.getManager("org.apache.tomcat.util.net.jsse.res"); 94 95 public JSSE14SocketFactory () { 96 } 97 98 99 /** 100 * Reads the keystore and initializes the SSL socket factory. 101 */ 102 /* SJSAS 6439313 103 void init() throws IOException{ 104 */ 105 // START SJSAS 6439313 106 public void init() throws IOException{ 107 // END SJSAS 6439313 108 try { 109 110 String clientAuthStr = (String) attributes.get("clientauth"); 111 if (clientAuthStr != null){ 112 clientAuth = Boolean.valueOf(clientAuthStr).booleanValue(); 113 } 114 115 // SSL protocol variant (e.g., TLS, SSL v3, etc.) 116 String protocol = (String) attributes.get("protocol"); 117 if (protocol == null) { 118 protocol = defaultProtocol; 119 } 120 121 // Certificate encoding algorithm (e.g., SunX509) 122 String algorithm = (String) attributes.get("algorithm"); 123 if (algorithm == null) { 124 algorithm = defaultAlgorithm; 125 } 126 127 // Create and init SSLContext 128 /* SJSAS 6439313 129 SSLContext context = SSLContext.getInstance(protocol); 130 */ 131 132 // START SJSAS 6439313 133 context = SSLContext.getInstance(protocol); 134 // END SJSAS 6439313 135 136 // Configure SSL session timeout and cache size 137 configureSSLSessionContext(context.getServerSessionContext()); 138 139 String trustAlgorithm = (String)attributes.get("truststoreAlgorithm"); 140 if (trustAlgorithm == null) { 141 trustAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); 142 } 143 144 context.init(getKeyManagers(algorithm, 145 (String) attributes.get("keyAlias")), 146 getTrustManagers(trustAlgorithm), 147 new SecureRandom()); 148 149 // create proxy 150 sslProxy = context.getServerSocketFactory(); 151 152 // Determine which cipher suites to enable 153 String requestedCiphers = (String)attributes.get("ciphers"); 154 if (requestedCiphers != null) { 155 enabledCiphers = getEnabledCiphers(requestedCiphers, 156 sslProxy.getSupportedCipherSuites()); 157 } 158 159 } catch(Exception e) { 160 if( e instanceof IOException ) 161 throw (IOException)e; 162 throw new IOException(e.getMessage()); 163 } 164 } 165 166 /** 167 * Gets the initialized key managers. 168 */ 169 protected KeyManager[] getKeyManagers(String algorithm, 170 String keyAlias) 171 throws Exception { 172 173 KeyManager[] kms = null; 174 175 String keystorePass = getKeystorePassword(); 176 177 KeyStore ks = getKeystore(keystorePass); 178 if (keyAlias != null && !ks.isKeyEntry(keyAlias)) { 179 throw new IOException(sm.getString("jsse.alias_no_key_entry", keyAlias)); 180 } 181 182 KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); 183 kmf.init(ks, keystorePass.toCharArray()); 184 185 kms = kmf.getKeyManagers(); 186 if (keyAlias != null) { 187 // START SJSAS 6266949 188 /* 189 if (JSSESocketFactory.defaultKeystoreType.equals(keystoreType)) { 190 keyAlias = keyAlias.toLowerCase(); 191 } 192 */ 193 //END SJSAS 6266949 194 195 for(int i=0; i<kms.length; i++) { 196 kms[i] = new JSSEKeyManager((X509KeyManager)kms[i], keyAlias); 197 } 198 } 199 200 return kms; 201 } 202 203 /** 204 * Gets the intialized trust managers. 205 */ 206 protected TrustManager[] getTrustManagers(String algorithm) 207 throws Exception { 208 209 String crlf = (String) attributes.get("crlFile"); 210 211 TrustManager[] tms = null; 212 213 KeyStore trustStore = getTrustStore(); 214 if (trustStore != null) { 215 if (crlf == null) { 216 TrustManagerFactory tmf = 217 TrustManagerFactory.getInstance(algorithm); 218 tmf.init(trustStore); 219 tms = tmf.getTrustManagers(); 220 } else { 221 TrustManagerFactory tmf = 222 TrustManagerFactory.getInstance(algorithm); 223 CertPathParameters params = getParameters(algorithm, crlf, 224 trustStore); 225 ManagerFactoryParameters mfp = 226 new CertPathTrustManagerParameters(params); 227 tmf.init(mfp); 228 tms = tmf.getTrustManagers(); 229 } 230 } 231 232 return tms; 233 } 234 235 236 /** 237 * Return the initialization parameters for the TrustManager. 238 * Currently, only the default <code>PKIX</code> is supported. 239 * 240 * @param algorithm The algorithm to get parameters for. 241 * @param crlf The path to the CRL file. 242 * @param trustStore The configured TrustStore. 243 * @return The parameters including the CRLs and TrustStore. 244 */ 245 protected CertPathParameters getParameters(String algorithm, 246 String crlf, 247 KeyStore trustStore) 248 throws Exception { 249 250 CertPathParameters params = null; 251 if ("PKIX".equalsIgnoreCase(algorithm)) { 252 PKIXBuilderParameters xparams = 253 new PKIXBuilderParameters(trustStore, 254 new X509CertSelector()); 255 Collection crls = getCRLs(crlf); 256 CertStoreParameters csp = new CollectionCertStoreParameters(crls); 257 CertStore store = CertStore.getInstance("Collection", csp); 258 xparams.addCertStore(store); 259 xparams.setRevocationEnabled(true); 260 String trustLength = (String)attributes.get("trustMaxCertLength"); 261 if (trustLength != null) { 262 try { 263 xparams.setMaxPathLength(Integer.parseInt(trustLength)); 264 } catch(Exception ex) { 265 log.warn("Bad maxCertLength: " + trustLength); 266 } 267 } 268 params = xparams; 269 } else { 270 throw new CRLException("CRLs not supported for type: " 271 + algorithm); 272 } 273 return params; 274 } 275 276 277 /** 278 * Load the collection of CRLs. 279 */ 280 protected Collection<? extends CRL> getCRLs(String crlf) 281 throws IOException, CRLException, CertificateException { 282 283 File crlFile = new File(crlf); 284 if (!crlFile.isAbsolute()) { 285 crlFile = new File(System.getProperty("catalina.base"), crlf); 286 } 287 Collection<? extends CRL> crls = null; 288 InputStream is = null; 289 try { 290 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 291 is = new FileInputStream(crlFile); 292 crls = cf.generateCRLs(is); 293 } catch(IOException iex) { 294 throw iex; 295 } catch(CRLException crle) { 296 throw crle; 297 } catch(CertificateException ce) { 298 throw ce; 299 } finally { 300 if (is != null) { 301 try { 302 is.close(); 303 } catch (Exception ex) { 304 } 305 } 306 } 307 308 return crls; 309 } 310 311 312 protected void setEnabledProtocols(SSLServerSocket socket, String []protocols){ 313 if (protocols != null) { 314 socket.setEnabledProtocols(protocols); 315 } 316 } 317 318 protected String[] getEnabledProtocols(SSLServerSocket socket, 319 String requestedProtocols){ 320 String[] supportedProtocols = socket.getSupportedProtocols(); 321 322 String[] enabledProtocols = null; 323 324 if (requestedProtocols != null) { 325 Vector vec = null; 326 String protocol = requestedProtocols; 327 int index = requestedProtocols.indexOf(','); 328 if (index != -1) { 329 int fromIndex = 0; 330 while (index != -1) { 331 protocol = requestedProtocols.substring(fromIndex, index).trim(); 332 if (protocol.length() > 0) { 333 /* 334 * Check to see if the requested protocol is among the 335 * supported protocols, i.e., may be enabled 336 */ 337 for (int i=0; supportedProtocols != null 338 && i<supportedProtocols.length; i++) { 339 if (supportedProtocols[i].equals(protocol)) { 340 if (vec == null) { 341 vec = new Vector(); 342 } 343 vec.addElement(protocol); 344 break; 345 } 346 } 347 } 348 fromIndex = index+1; 349 index = requestedProtocols.indexOf(',', fromIndex); 350 } // while 351 protocol = requestedProtocols.substring(fromIndex); 352 } 353 354 if (protocol != null) { 355 protocol = protocol.trim(); 356 if (protocol.length() > 0) { 357 /* 358 * Check to see if the requested protocol is among the 359 * supported protocols, i.e., may be enabled 360 */ 361 for (int i=0; supportedProtocols != null 362 && i<supportedProtocols.length; i++) { 363 if (supportedProtocols[i].equals(protocol)) { 364 if (vec == null) { 365 vec = new Vector(); 366 } 367 vec.addElement(protocol); 368 break; 369 } 370 } 371 } 372 } 373 374 if (vec != null) { 375 enabledProtocols = new String[vec.size()]; 376 vec.copyInto(enabledProtocols); 377 } 378 } 379 380 return enabledProtocols; 381 } 382 383 384 /* 385 * Configures the given SSLSessionContext. 386 * 387 * @param sslSessionCtxt The SSLSessionContext to configure 388 */ 389 private void configureSSLSessionContext(SSLSessionContext sslSessionCtxt) { 390 391 String attrValue = (String) attributes.get("sslSessionTimeout"); 392 if (attrValue != null) { 393 sslSessionCtxt.setSessionTimeout( 394 Integer.valueOf(attrValue).intValue()); 395 } 396 397 attrValue = (String) attributes.get("ssl3SessionTimeout"); 398 if (attrValue != null) { 399 sslSessionCtxt.setSessionTimeout( 400 Integer.valueOf(attrValue).intValue()); 401 } 402 403 attrValue = (String) attributes.get("sslSessionCacheSize"); 404 if (attrValue != null) { 405 sslSessionCtxt.setSessionCacheSize( 406 Integer.valueOf(attrValue).intValue()); 407 } 408 } 409 410 }