001: /* tjws - SSLAcceptor.java
002: * Copyright (C) 1999-2007 Dmitriy Rogatkin. All rights reserved.
003: * Redistribution and use in source and binary forms, with or without
004: * modification, are permitted provided that the following conditions
005: * are met:
006: * 1. Redistributions of source code must retain the above copyright
007: * notice, this list of conditions and the following disclaimer.
008: * 2. Redistributions in binary form must reproduce the above copyright
009: * notice, this list of conditions and the following disclaimer in the
010: * documentation and/or other materials provided with the distribution.
011: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
012: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
013: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
014: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
015: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
016: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
017: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
018: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
019: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
020: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
021: * SUCH DAMAGE.
022: *
023: * Visit http://tjws.sourceforge.net to get the latest infromation
024: * about Rogatkin's products.
025: * $Id: SSLAcceptor.java,v 1.1 2007/02/22 06:08:45 rogatkin Exp $
026: * Created on Feb 21, 2007
027: * @author dmitriy
028: */
029: package Acme.Serve;
030:
031: import java.io.File;
032: import java.io.FileInputStream;
033: import java.io.IOException;
034: import java.net.InetAddress;
035: import java.net.ServerSocket;
036: import java.net.Socket;
037: import java.security.KeyStore;
038: import java.security.Security;
039: import java.util.Map;
040:
041: import javax.net.ssl.KeyManagerFactory;
042: import javax.net.ssl.SSLContext;
043: import javax.net.ssl.SSLServerSocket;
044:
045: import Acme.Serve.Serve.Acceptor;
046:
047: public class SSLAcceptor implements Acceptor {
048: public static final String ARG_ALGORITHM = "algorithm"; // SUNX509
049:
050: public static final String ARG_CLIENTAUTH = "clientAuth"; // false
051:
052: public static final String ARG_KEYSTOREFILE = "keystoreFile"; // System.getProperty("user.home") + File.separator + ".keystore";
053:
054: public static final String ARG_KEYSTOREPASS = "keystorePass"; // KEYSTOREPASS
055:
056: public static final String ARG_KEYSTORETYPE = "keystoreType"; // KEYSTORETYPE
057:
058: public static final String ARG_KEYPASS = "keyPass"; //
059:
060: public static final String ARG_PROTOCOL = "protocol"; // TLS
061:
062: public static final String ARG_BACKLOG = Serve.ARG_BACKLOG;
063:
064: public static final String ARG_IFADDRESS = "ifAddress";
065:
066: public static final String ARG_PORT = "ssl-port";
067:
068: public static final String PROTOCOL_HANDLER = "com.sun.net.ssl.internal.www.protocol";
069:
070: /**
071: * The name of the system property containing a "|" delimited list of
072: * protocol handler packages.
073: */
074: public static final String PROTOCOL_PACKAGES = "java.protocol.handler.pkgs";
075:
076: /**
077: * Certificate encoding algorithm to be used.
078: */
079: public final static String SUNX509 = "SunX509";
080:
081: /**
082: * default SSL port
083: */
084: public final static int PORT = 8443;
085:
086: /**
087: * default backlog
088: */
089: public final static int BACKLOG = 1000;
090:
091: /**
092: * Storeage type of the key store file to be used.
093: */
094: public final static String KEYSTORETYPE = "JKS";
095:
096: /**
097: * SSL protocol variant to use.
098: */
099: public final static String TLS = "TLS";
100:
101: /**
102: * SSL protocol variant to use.
103: */
104: public static final String protocol = TLS;
105:
106: /**
107: * Password for accessing the key store file.
108: */
109: private static final String KEYSTOREPASS = "123456";
110:
111: /**
112: * Pathname to the key store file to be used.
113: */
114: protected String keystoreFile = System.getProperty("user.home")
115: + File.separator + ".keystore";
116:
117: protected ServerSocket socket;
118:
119: private String getKeystoreFile() {
120: return (this .keystoreFile);
121: }
122:
123: public Socket accept() throws IOException {
124: return socket.accept();
125: }
126:
127: public void destroy() throws IOException {
128: try {
129: socket.close();
130: } finally {
131: socket = null;
132: }
133: }
134:
135: public void init(Map inProperties, Map outProperties)
136: throws IOException {
137: javax.net.ssl.SSLServerSocketFactory sslSoc = null;
138: // init keystore
139: KeyStore keyStore = null;
140: FileInputStream istream = null;
141: String keystorePass = null;
142:
143: try {
144: String keystoreType = getWithDefault(inProperties,
145: ARG_KEYSTORETYPE, KEYSTORETYPE);
146: keyStore = KeyStore.getInstance(keystoreType);
147: String keystoreFile = (String) inProperties
148: .get(ARG_KEYSTOREFILE);
149: if (keystoreFile == null)
150: keystoreFile = getKeystoreFile();
151: istream = new FileInputStream(keystoreFile);
152: keystorePass = getWithDefault(inProperties,
153: ARG_KEYSTOREPASS, KEYSTOREPASS);
154: keyStore.load(istream, keystorePass.toCharArray());
155: } catch (Exception e) {
156: System.err.println("initKeyStore: " + e);
157: e.printStackTrace();
158: throw new IOException(e.toString());
159: } finally {
160: if (istream != null)
161: istream.close();
162: }
163:
164: try {
165:
166: // Register the JSSE security Provider (if it is not already there)
167: try {
168: Security
169: .addProvider((java.security.Provider) Class
170: .forName(
171: "com.sun.net.ssl.internal.ssl.Provider")
172: .newInstance());
173: } catch (Throwable t) {
174: t.printStackTrace();
175: throw new IOException(t.toString());
176: }
177:
178: // Create an SSL context used to create an SSL socket factory
179: String protocol = getWithDefault(inProperties,
180: ARG_PROTOCOL, TLS);
181: SSLContext context = SSLContext.getInstance(protocol);
182:
183: // Create the key manager factory used to extract the server key
184: String algorithm = getWithDefault(inProperties,
185: ARG_ALGORITHM, SUNX509);
186: KeyManagerFactory keyManagerFactory = KeyManagerFactory
187: .getInstance(algorithm);
188:
189: String keyPass = getWithDefault(inProperties, ARG_KEYPASS,
190: keystorePass);
191:
192: keyManagerFactory.init(keyStore, keyPass.toCharArray());
193:
194: // Initialize the context with the key managers
195: context.init(keyManagerFactory.getKeyManagers(), null,
196: new java.security.SecureRandom());
197:
198: // Create the proxy and return
199: sslSoc = context.getServerSocketFactory();
200:
201: } catch (Exception e) {
202: System.err.println("SSLsocket creation: " + e);
203: e.printStackTrace();
204: throw new IOException(e.toString());
205: }
206:
207: int port = PORT;
208: if (inProperties.get(ARG_PORT) != null)
209: try {
210: port = Integer.parseInt((String) inProperties
211: .get(ARG_PORT));
212: } catch (NumberFormatException nfe) {
213:
214: }
215: else if (inProperties.get(Serve.ARG_PORT) != null)
216: port = ((Integer) inProperties.get(ARG_PORT)).intValue();
217: if (inProperties.get(ARG_BACKLOG) == null)
218: if (inProperties.get(ARG_IFADDRESS) == null)
219: socket = sslSoc.createServerSocket(port);
220: else
221: socket = sslSoc.createServerSocket(port, BACKLOG,
222: InetAddress.getByName((String) inProperties
223: .get(ARG_IFADDRESS)));
224: else if (inProperties.get(ARG_IFADDRESS) == null)
225: socket = sslSoc.createServerSocket(port,
226: ((Integer) inProperties.get(ARG_BACKLOG))
227: .intValue());
228: else
229: socket = sslSoc.createServerSocket(port,
230: ((Integer) inProperties.get(ARG_BACKLOG))
231: .intValue(), InetAddress
232: .getByName((String) inProperties
233: .get(ARG_IFADDRESS)));
234:
235: initServerSocket(socket, "true".equals(inProperties
236: .get(ARG_CLIENTAUTH)));
237: if (outProperties != null)
238: outProperties.put(Serve.ARG_BINDADDRESS, socket
239: .getInetAddress().getHostName());
240: }
241:
242: /**
243: * Register our URLStreamHandler for the "https:" protocol.
244: */
245: protected static void initHandler() {
246:
247: String packages = System.getProperty(PROTOCOL_PACKAGES);
248: if (packages == null)
249: packages = PROTOCOL_HANDLER;
250: else if (packages.indexOf(PROTOCOL_HANDLER) < 0)
251: packages += "|" + PROTOCOL_HANDLER;
252: System.setProperty(PROTOCOL_PACKAGES, packages);
253:
254: }
255:
256: static {
257: initHandler();
258: }
259:
260: /**
261: * Set the requested properties for this server socket.
262: *
263: * @param ssocket The server socket to be configured
264: */
265: protected void initServerSocket(ServerSocket ssocket,
266: boolean clientAuth) {
267:
268: SSLServerSocket socket = (SSLServerSocket) ssocket;
269:
270: // Enable all available cipher suites when the socket is connected
271: String cipherSuites[] = socket.getSupportedCipherSuites();
272: socket.setEnabledCipherSuites(cipherSuites);
273: // Set client authentication if necessary
274: socket.setNeedClientAuth(clientAuth);
275: }
276:
277: private String getWithDefault(Map args, String name, String defValue) {
278: String result = (String) args.get(name);
279: if (result == null)
280: return defValue;
281: return result;
282: }
283: }
|