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