1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.tomcat.util.net.puretls; 19 20 import java.io.IOException; 21 import java.net.InetAddress; 22 import java.net.ServerSocket; 23 import java.net.Socket; 24 import java.net.SocketException; 25 import java.util.Vector; 26 27 import COM.claymoresystems.ptls.SSLContext; 28 import COM.claymoresystems.ptls.SSLException; 29 import COM.claymoresystems.ptls.SSLServerSocket; 30 import COM.claymoresystems.ptls.SSLSocket; 31 import COM.claymoresystems.sslg.SSLPolicyInt; 32 33 /** 34 * SSL server socket factory--wraps PureTLS 35 * 36 * @author Eric Rescorla 37 * 38 * some sections of this file cribbed from SSLSocketFactory 39 * (the JSSE socket factory) 40 * 41 */ 42 43 public class PureTLSSocketFactory 44 extends org.apache.tomcat.util.net.ServerSocketFactory 45 { 46 static org.apache.commons.logging.Log logger = 47 org.apache.commons.logging.LogFactory.getLog(PureTLSSocketFactory.class); 48 static String defaultProtocol = "TLS"; 49 static boolean defaultClientAuth = false; 50 static String defaultKeyStoreFile = "server.pem"; 51 static String defaultKeyPass = "password"; 52 static String defaultRootFile = "root.pem"; 53 static String defaultRandomFile = "random.pem"; 54 55 private COM.claymoresystems.ptls.SSLContext context=null; 56 57 public PureTLSSocketFactory() { 58 } 59 60 public ServerSocket createSocket(int port) 61 throws IOException 62 { 63 init(); 64 return new SSLServerSocket(context,port); 65 } 66 67 public ServerSocket createSocket(int port, int backlog) 68 throws IOException 69 { 70 init(); 71 ServerSocket tmp; 72 73 try { 74 tmp=new SSLServerSocket(context,port,backlog); 75 } 76 catch (IOException e){ 77 throw e; 78 } 79 return tmp; 80 } 81 82 public ServerSocket createSocket(int port, int backlog, 83 InetAddress ifAddress) 84 throws IOException 85 { 86 init(); 87 return new SSLServerSocket(context,port,backlog,ifAddress); 88 } 89 90 private void init() 91 throws IOException 92 { 93 if(context!=null) 94 return; 95 96 boolean clientAuth=defaultClientAuth; 97 98 try { 99 String keyStoreFile=(String)attributes.get("keystore"); 100 if(keyStoreFile==null) keyStoreFile=defaultKeyStoreFile; 101 102 String keyPass=(String)attributes.get("keypass"); 103 if(keyPass==null) keyPass=defaultKeyPass; 104 105 String rootFile=(String)attributes.get("rootfile"); 106 if(rootFile==null) rootFile=defaultRootFile; 107 108 String randomFile=(String)attributes.get("randomfile"); 109 if(randomFile==null) randomFile=defaultRandomFile; 110 111 String protocol=(String)attributes.get("protocol"); 112 if(protocol==null) protocol=defaultProtocol; 113 114 String clientAuthStr=(String)attributes.get("clientauth"); 115 if(clientAuthStr != null){ 116 if(clientAuthStr.equals("true")){ 117 clientAuth=true; 118 } else if(clientAuthStr.equals("false")) { 119 clientAuth=false; 120 } else { 121 throw new IOException("Invalid value '" + 122 clientAuthStr + 123 "' for 'clientauth' parameter:"); 124 } 125 } 126 127 SSLContext tmpContext=new SSLContext(); 128 try { 129 tmpContext.loadRootCertificates(rootFile); 130 } catch(IOException iex) { 131 if(logger.isDebugEnabled()) 132 logger.debug("Error loading Client Root Store: " + 133 rootFile,iex); 134 } 135 tmpContext.loadEAYKeyFile(keyStoreFile,keyPass); 136 tmpContext.useRandomnessFile(randomFile,keyPass); 137 138 SSLPolicyInt policy=new SSLPolicyInt(); 139 policy.requireClientAuth(clientAuth); 140 policy.handshakeOnConnect(false); 141 policy.waitOnClose(false); 142 short [] enabledCiphers = getEnabledCiphers(policy.getCipherSuites()); 143 if( enabledCiphers != null ) { 144 policy.setCipherSuites(enabledCiphers); 145 } 146 tmpContext.setPolicy(policy); 147 context=tmpContext; 148 } catch (Exception e){ 149 logger.info("Error initializing SocketFactory",e); 150 throw new IOException(e.getMessage()); 151 } 152 } 153 154 /* 155 * Determines the SSL cipher suites to be enabled. 156 * 157 * @return Array of SSL cipher suites to be enabled, or null if the 158 * cipherSuites property was not specified (meaning that all supported 159 * cipher suites are to be enabled) 160 */ 161 private short [] getEnabledCiphers(short [] supportedCiphers) { 162 163 short [] enabledCiphers = null; 164 165 String attrValue = (String)attributes.get("ciphers"); 166 if (attrValue != null) { 167 Vector vec = null; 168 int fromIndex = 0; 169 int index = attrValue.indexOf(',', fromIndex); 170 while (index != -1) { 171 String cipher = attrValue.substring(fromIndex, index).trim(); 172 int cipherValue = SSLPolicyInt.getCipherSuiteNumber(cipher); 173 /* 174 * Check to see if the requested cipher is among the supported 175 * ciphers, i.e., may be enabled 176 */ 177 if( cipherValue >= 0) { 178 for (int i=0; supportedCiphers != null 179 && i<supportedCiphers.length; i++) { 180 181 if (cipherValue == supportedCiphers[i]) { 182 if (vec == null) { 183 vec = new Vector(); 184 } 185 vec.addElement(new Integer(cipherValue)); 186 break; 187 } 188 } 189 } 190 fromIndex = index+1; 191 index = attrValue.indexOf(',', fromIndex); 192 } 193 194 if (vec != null) { 195 int nCipher = vec.size(); 196 enabledCiphers = new short[nCipher]; 197 for(int i=0; i < nCipher; i++) { 198 Integer value = (Integer)vec.elementAt(i); 199 enabledCiphers[i] = value.shortValue(); 200 } 201 } 202 } 203 204 return enabledCiphers; 205 206 } 207 208 public Socket acceptSocket(ServerSocket socket) 209 throws IOException 210 { 211 try { 212 Socket sock=socket.accept(); 213 return sock; 214 } catch (SSLException e){ 215 logger.debug("SSL handshake error",e); 216 throw new SocketException("SSL handshake error" + e.toString()); 217 } 218 } 219 220 public void handshake(Socket sock) 221 throws IOException 222 { 223 ((SSLSocket)sock).handshake(); 224 } 225 } 226 227 228 229 230