001/*
002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/SSLServer.java $
003 * $Revision: 121 $
004 * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
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 javax.net.ssl.SSLContext;
035import javax.net.ssl.SSLServerSocketFactory;
036import java.io.File;
037import java.io.IOException;
038import java.net.InetAddress;
039import java.net.ServerSocket;
040import java.security.GeneralSecurityException;
041import java.security.KeyManagementException;
042import java.security.KeyStoreException;
043import java.security.NoSuchAlgorithmException;
044import java.security.cert.CertificateException;
045import java.security.cert.X509Certificate;
046import java.util.Collection;
047import java.util.List;
048import java.util.Properties;
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 May 1, 2006
055 */
056public class SSLServer extends SSLServerSocketFactory {
057    protected final SSL ssl;
058
059    public SSLServer()
060        throws GeneralSecurityException, IOException {
061        this.ssl = new SSL();
062        // client certs aren't usually tied down to a single host (and who knows
063        // if the DNS reverse-lookup will work!).
064        setCheckHostname(false);
065
066        // If "javax.net.ssl.keyStore" is set, then we won't bother with this
067        // silly SSLServer default behaviour.
068        if (!ssl.usingSystemProperties) {
069            // commons-ssl default KeyMaterial will be
070            //  ~/.keystore with a password of "changeit".
071            useDefaultKeyMaterial();
072        }
073    }
074
075    /**
076     * Tries to extract the TrustMaterial and KeyMaterial being used by a Tomcat
077     * SSL server (usually on 8443) by analyzing Tomcat's "server.xml" file.  If
078     * the extraction is successful, the TrustMaterial and KeyMaterial are
079     * applied to this SSLServer.
080     *
081     * @return true if the operation was successful.
082     * @throws GeneralSecurityException setKeyMaterial() failed
083     * @throws IOException              setKeyMaterial() failed
084     */
085    public boolean useTomcatSSLMaterial()
086        throws GeneralSecurityException, IOException {
087        // If running inside Tomcat, let's try to re-use Tomcat's SSL
088        // certificate for our own stuff (e.g. RMI-SSL).
089        Integer p8443 = new Integer(8443);
090        KeyMaterial km;
091        TrustMaterial tm;
092        km = (KeyMaterial) TomcatServerXML.KEY_MATERIAL_BY_PORT.get(p8443);
093        tm = (TrustMaterial) TomcatServerXML.TRUST_MATERIAL_BY_PORT.get(p8443);
094
095        // If 8443 isn't set, let's take lowest secure port.
096        km = km == null ? TomcatServerXML.KEY_MATERIAL : km;
097        tm = tm == null ? TomcatServerXML.TRUST_MATERIAL : tm;
098        boolean success = false;
099        if (km != null) {
100            setKeyMaterial(km);
101            success = true;
102            if (tm != null && !TrustMaterial.DEFAULT.equals(tm)) {
103                setTrustMaterial(tm);
104            }
105        }
106        return success;
107    }
108
109    private boolean useDefaultKeyMaterial()
110        throws GeneralSecurityException, IOException {
111        // If we're not able to re-use Tomcat's SSLServerSocket configuration,
112        // commons-ssl default KeyMaterial will be  ~/.keystore with a password
113        // of "changeit".
114        Properties props = System.getProperties();
115        boolean pwdSet = props.containsKey("javax.net.ssl.keyStorePassword");
116        String pwd = props.getProperty("javax.net.ssl.keyStorePassword");
117        pwd = pwdSet ? pwd : "changeit";
118
119        String userHome = System.getProperty("user.home");
120        String path = userHome + "/.keystore";
121        File f = new File(path);
122        boolean success = false;
123        if (f.exists()) {
124            KeyMaterial km = null;
125            try {
126                km = new KeyMaterial(path, pwd.toCharArray());
127            }
128            catch (Exception e) {
129                // Don't want to blowup just because this silly default
130                // behaviour didn't work out.
131                if (pwdSet) {
132                    // Buf if the user has specified a non-standard password for
133                    // "javax.net.ssl.keyStorePassword", then we will warn them
134                    // that things didn't work out.
135                    System.err.println("commons-ssl automatic loading of [" + path + "] failed. ");
136                    System.err.println(e);
137                }
138            }
139            if (km != null) {
140                setKeyMaterial(km);
141                success = true;
142            }
143        }
144        return success;
145    }
146
147    public void addTrustMaterial(TrustChain trustChain)
148        throws NoSuchAlgorithmException, KeyStoreException,
149        KeyManagementException, IOException, CertificateException {
150        ssl.addTrustMaterial(trustChain);
151    }
152
153    public void setTrustMaterial(TrustChain trustChain)
154        throws NoSuchAlgorithmException, KeyStoreException,
155        KeyManagementException, IOException, CertificateException {
156        ssl.setTrustMaterial(trustChain);
157    }
158
159    public void setKeyMaterial(KeyMaterial keyMaterial)
160        throws NoSuchAlgorithmException, KeyStoreException,
161        KeyManagementException, IOException, CertificateException {
162        ssl.setKeyMaterial(keyMaterial);
163    }
164
165    public void addAllowedName(String s) { ssl.addAllowedName(s); }
166
167    public void addAllowedNames(Collection c) { ssl.addAllowedNames(c); }
168
169    public void clearAllowedNames() { ssl.clearAllowedNames(); }
170
171    public void setCheckCRL(boolean b) { ssl.setCheckCRL(b); }
172
173    public void setCheckExpiry(boolean b) { ssl.setCheckExpiry(b); }
174
175    public void setCheckHostname(boolean b) { ssl.setCheckHostname(b); }
176
177    public void setConnectTimeout(int i) { ssl.setConnectTimeout(i); }
178
179    public void setDefaultProtocol(String s) { ssl.setDefaultProtocol(s); }
180
181    public void useDefaultJavaCiphers() { ssl.useDefaultJavaCiphers(); }
182
183    public void useStrongCiphers() { ssl.useStrongCiphers(); }
184
185    public void setEnabledCiphers(String[] ciphers) {
186        ssl.setEnabledCiphers(ciphers);
187    }
188
189    public void setEnabledProtocols(String[] protocols) {
190        ssl.setEnabledProtocols(protocols);
191    }
192
193    public void setHostnameVerifier(HostnameVerifier verifier) {
194        ssl.setHostnameVerifier(verifier);
195    }
196
197    public void setSoTimeout(int soTimeout) { ssl.setSoTimeout(soTimeout); }
198
199    public void setSSLWrapperFactory(SSLWrapperFactory wf) {
200        ssl.setSSLWrapperFactory(wf);
201    }
202
203    public void setNeedClientAuth(boolean b) { ssl.setNeedClientAuth(b); }
204
205    public void setWantClientAuth(boolean b) { ssl.setWantClientAuth(b); }
206
207    public void setUseClientMode(boolean b) { ssl.setUseClientMode(b); }
208
209    public List getAllowedNames() { return ssl.getAllowedNames(); }
210
211    public X509Certificate[] getAssociatedCertificateChain() {
212        return ssl.getAssociatedCertificateChain();
213    }
214
215    public boolean getCheckCRL() { return ssl.getCheckCRL(); }
216
217    public boolean getCheckExpiry() { return ssl.getCheckExpiry(); }
218
219    public boolean getCheckHostname() { return ssl.getCheckHostname(); }
220
221    public int getConnectTimeout() { return ssl.getConnectTimeout(); }
222
223    public String getDefaultProtocol() { return ssl.getDefaultProtocol(); }
224
225    public String[] getEnabledCiphers() { return ssl.getEnabledCiphers(); }
226
227    public String[] getEnabledProtocols() { return ssl.getEnabledProtocols(); }
228
229    public HostnameVerifier getHostnameVerifier() {
230        return ssl.getHostnameVerifier();
231    }
232
233    public int getSoTimeout() { return ssl.getSoTimeout(); }
234
235    public SSLWrapperFactory getSSLWrapperFactory() {
236        return ssl.getSSLWrapperFactory();
237    }
238
239    public boolean getNeedClientAuth() { return ssl.getNeedClientAuth(); }
240
241    public boolean getWantClientAuth() { return ssl.getWantClientAuth(); }
242
243    public boolean getUseClientMode() { /* SSLServer's default is false. */
244        return !ssl.getUseClientModeDefault() && ssl.getUseClientMode();
245    }
246
247    public SSLContext getSSLContext() throws GeneralSecurityException, IOException {
248        return ssl.getSSLContext();
249    }
250
251    public TrustChain getTrustChain() { return ssl.getTrustChain(); }
252
253    public X509Certificate[] getCurrentClientChain() {
254        return ssl.getCurrentClientChain();
255    }
256
257    public String[] getDefaultCipherSuites() {
258        return ssl.getDefaultCipherSuites();
259    }
260
261    public String[] getSupportedCipherSuites() {
262        return ssl.getSupportedCipherSuites();
263    }
264
265    public ServerSocket createServerSocket() throws IOException {
266        return ssl.createServerSocket();
267    }
268
269    public ServerSocket createServerSocket(int port)
270        throws IOException {
271        return createServerSocket(port, 50);
272    }
273
274    public ServerSocket createServerSocket(int port, int backlog)
275        throws IOException {
276        return createServerSocket(port, backlog, null);
277    }
278
279    /**
280     * Attempts to get a new socket connection to the given host within the
281     * given time limit.
282     *
283     * @param localHost the local host name/IP to bind against (null == ANY)
284     * @param port      the port to listen on
285     * @param backlog   number of connections allowed to queue up for accept().
286     * @return SSLServerSocket a new server socket
287     * @throws IOException if an I/O error occurs while creating thesocket
288     */
289    public ServerSocket createServerSocket(int port, int backlog,
290                                           InetAddress localHost)
291        throws IOException {
292        return ssl.createServerSocket(port, backlog, localHost);
293    }
294
295}