001: // jTDS JDBC Driver for Microsoft SQL Server and Sybase
002: //Copyright (C) 2004 The jTDS Project
003: //
004: //This library is free software; you can redistribute it and/or
005: //modify it under the terms of the GNU Lesser General Public
006: //License as published by the Free Software Foundation; either
007: //version 2.1 of the License, or (at your option) any later version.
008: //
009: //This library is distributed in the hope that it will be useful,
010: //but WITHOUT ANY WARRANTY; without even the implied warranty of
011: //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: //Lesser General Public License for more details.
013: //
014: //You should have received a copy of the GNU Lesser General Public
015: //License along with this library; if not, write to the Free Software
016: //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: //
018: package net.sourceforge.jtds.ssl;
019:
020: import java.io.IOException;
021: import java.net.InetAddress;
022: import java.net.Socket;
023: import java.net.UnknownHostException;
024: import java.security.GeneralSecurityException;
025: import java.security.KeyManagementException;
026: import java.security.NoSuchAlgorithmException;
027: import java.security.cert.X509Certificate;
028: import javax.net.SocketFactory;
029: import javax.net.ssl.SSLSocket;
030: import javax.net.ssl.SSLSocketFactory;
031:
032: import com.sun.net.ssl.SSLContext;
033: import com.sun.net.ssl.TrustManager;
034: import com.sun.net.ssl.X509TrustManager;
035:
036: import net.sourceforge.jtds.util.Logger;
037:
038: /**
039: * Used for acquiring a socket factory when SSL is enabled.
040: *
041: * @author Rob Worsnop
042: * @author Mike Hutchinson
043: * @version $Id: SocketFactories.java,v 1.8 2007/07/08 17:28:24 bheineman Exp $
044: */
045: public class SocketFactories {
046: /**
047: * Returns a socket factory, the behavior of which will depend on the SSL
048: * setting and whether or not the DB server supports SSL.
049: *
050: * @param ssl the SSL setting
051: * @param socket plain TCP/IP socket to wrap
052: */
053: public static SocketFactory getSocketFactory(String ssl,
054: Socket socket) {
055: return new TdsTlsSocketFactory(ssl, socket);
056: }
057:
058: /**
059: * The socket factory for creating sockets based on the SSL setting.
060: */
061: private static class TdsTlsSocketFactory extends SocketFactory {
062: private static SSLSocketFactory factorySingleton;
063:
064: private final String ssl;
065: private final Socket socket;
066:
067: /**
068: * Constructs a TdsTlsSocketFactory.
069: *
070: * @param ssl the SSL setting
071: * @param socket the TCP/IP socket to wrap
072: */
073: public TdsTlsSocketFactory(String ssl, Socket socket) {
074: this .ssl = ssl;
075: this .socket = socket;
076: }
077:
078: /**
079: * Create the SSL socket.
080: * <p/>
081: * NB. This method will actually create a connected socket over the
082: * TCP/IP network socket supplied via the constructor of this factory
083: * class.
084: */
085: public Socket createSocket(String host, int port)
086: throws IOException, UnknownHostException {
087: SSLSocket sslSocket = (SSLSocket) getFactory()
088: .createSocket(new TdsTlsSocket(socket), host, port,
089: true);
090: //
091: // See if connecting to local server.
092: // getLocalHost() will normally return the address of a real
093: // local network interface so we check that one and the loopback
094: // address localhost/127.0.0.1
095: //
096: // XXX: Disable TLS resume altogether, because the cause of local
097: // server failures is unknown and it also seems to sometiles occur
098: // with remote servers.
099: //
100: // if (socket.getInetAddress().equals(InetAddress.getLocalHost()) ||
101: // host.equalsIgnoreCase("localhost") || host.startsWith("127.")) {
102: // Resume session causes failures with a local server
103: // Invalidate the session to prevent resumes.
104: sslSocket.startHandshake(); // Any IOException thrown here
105: sslSocket.getSession().invalidate();
106: // Logger.println("TLS Resume disabled");
107: // }
108:
109: return sslSocket;
110: }
111:
112: /*
113: * (non-Javadoc)
114: *
115: * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int)
116: */
117: public Socket createSocket(InetAddress host, int port)
118: throws IOException {
119: return null;
120: }
121:
122: /*
123: * (non-Javadoc)
124: *
125: * @see javax.net.SocketFactory#createSocket(java.lang.String, int,
126: * java.net.InetAddress, int)
127: */
128: public Socket createSocket(String host, int port,
129: InetAddress localHost, int localPort)
130: throws IOException, UnknownHostException {
131: return null;
132: }
133:
134: /*
135: * (non-Javadoc)
136: *
137: * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int,
138: * java.net.InetAddress, int)
139: */
140: public Socket createSocket(InetAddress host, int port,
141: InetAddress localHost, int localPort)
142: throws IOException {
143: return null;
144: }
145:
146: /**
147: * Returns an SSLSocketFactory whose behavior will depend on the SSL
148: * setting.
149: *
150: * @return an <code>SSLSocketFactory</code>
151: */
152: private SSLSocketFactory getFactory() throws IOException {
153: try {
154: if (Ssl.SSL_AUTHENTICATE.equals(ssl)) {
155: // the default factory will produce a socket that authenticates
156: // the server using its certificate chain.
157: return (SSLSocketFactory) SSLSocketFactory
158: .getDefault();
159: } else {
160: // Our custom factory will not authenticate the server.
161: return factory();
162: }
163: } catch (GeneralSecurityException e) {
164: Logger.logException(e);
165: throw new IOException(e.getMessage());
166: }
167: }
168:
169: /**
170: * Returns an SSLSocketFactory whose sockets will not authenticate the
171: * server.
172: *
173: * @return an <code>SSLSocketFactory</code>
174: */
175: private static SSLSocketFactory factory()
176: throws NoSuchAlgorithmException, KeyManagementException {
177: if (factorySingleton == null) {
178: SSLContext ctx = SSLContext.getInstance("TLS");
179: ctx.init(null, trustManagers(), null);
180: factorySingleton = ctx.getSocketFactory();
181: }
182: return factorySingleton;
183: }
184:
185: private static TrustManager[] trustManagers() {
186: X509TrustManager tm = new X509TrustManager() {
187: public X509Certificate[] getAcceptedIssuers() {
188: return new X509Certificate[0];
189: }
190:
191: public boolean isClientTrusted(X509Certificate[] chain) {
192: return true;
193: }
194:
195: public boolean isServerTrusted(X509Certificate[] chain) {
196: return true;
197: }
198: };
199:
200: return new X509TrustManager[] { tm };
201: }
202:
203: }
204: }
|