001/*
002 * $HeadURL: file:///opt/dev/not-yet-commons-ssl-SVN-repo/tags/commons-ssl-0.3.17/src/java/org/apache/commons/ssl/Java14.java $
003 * $Revision: 187 $
004 * $Date: 2015-03-16 14:27:25 -0700 (Mon, 16 Mar 2015) $
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 java.io.IOException;
035import java.lang.reflect.InvocationTargetException;
036import java.lang.reflect.Method;
037import java.net.InetAddress;
038import java.net.InetSocketAddress;
039import java.net.ServerSocket;
040import java.net.Socket;
041import java.security.KeyManagementException;
042import java.security.KeyStore;
043import java.security.KeyStoreException;
044import java.security.NoSuchAlgorithmException;
045import java.security.UnrecoverableKeyException;
046import java.security.cert.Certificate;
047import java.security.cert.CertificateException;
048import java.security.cert.X509Certificate;
049
050import javax.net.SocketFactory;
051import javax.net.ssl.KeyManager;
052import javax.net.ssl.KeyManagerFactory;
053import javax.net.ssl.SSLContext;
054import javax.net.ssl.SSLPeerUnverifiedException;
055import javax.net.ssl.SSLServerSocket;
056import javax.net.ssl.SSLServerSocketFactory;
057import javax.net.ssl.SSLSession;
058import javax.net.ssl.SSLSocket;
059import javax.net.ssl.SSLSocketFactory;
060import javax.net.ssl.TrustManager;
061import javax.net.ssl.TrustManagerFactory;
062import javax.net.ssl.X509KeyManager;
063import javax.net.ssl.X509TrustManager;
064
065
066/**
067 * @author Credit Union Central of British Columbia
068 * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
069 * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
070 * @since 30-Jun-2006
071 */
072public final class Java14 extends JavaImpl {
073    private static Java14 instance = new Java14();
074
075    private Java14() {
076        try {
077            SSLSocketFactory.getDefault().createSocket();
078        }
079        catch (IOException ioe) {
080            ioe.hashCode();
081        }
082    }
083
084    public static Java14 getInstance() {
085        return instance;
086    }
087
088    public final String getVersion() {
089        return "Java14";
090    }
091
092    protected final String retrieveSubjectX500(X509Certificate cert) {
093        return cert.getSubjectX500Principal().toString();
094    }
095
096    protected final String retrieveIssuerX500(X509Certificate cert) {
097        return cert.getIssuerX500Principal().toString();
098    }
099
100    protected final Certificate[] retrievePeerCerts(SSLSession sslSession)
101        throws SSLPeerUnverifiedException {
102        return sslSession.getPeerCertificates();
103    }
104
105    protected final Object buildKeyManagerFactory(KeyStore ks, char[] password)
106        throws NoSuchAlgorithmException, KeyStoreException,
107        UnrecoverableKeyException {
108        String alg = KeyManagerFactory.getDefaultAlgorithm();
109        KeyManagerFactory kmf = KeyManagerFactory.getInstance(alg);
110        kmf.init(ks, password);
111        return kmf;
112    }
113
114    protected final Object buildTrustManagerFactory(KeyStore ks)
115        throws NoSuchAlgorithmException, KeyStoreException {
116        String alg = TrustManagerFactory.getDefaultAlgorithm();
117        TrustManagerFactory tmf = TrustManagerFactory.getInstance(alg);
118        tmf.init(ks);
119        return tmf;
120    }
121
122    protected final Object[] retrieveKeyManagers(Object keyManagerFactory) {
123        KeyManagerFactory kmf = (KeyManagerFactory) keyManagerFactory;
124        return kmf.getKeyManagers();
125    }
126
127    protected final Object[] retrieveTrustManagers(Object trustManagerFactory) {
128        TrustManagerFactory tmf = (TrustManagerFactory) trustManagerFactory;
129        return tmf.getTrustManagers();
130    }
131
132    protected final SSLSocketFactory buildSSLSocketFactory(Object ssl) {
133        return ((SSLContext) ssl).getSocketFactory();
134    }
135
136    protected final SSLServerSocketFactory buildSSLServerSocketFactory(Object ssl) {
137        return ((SSLContext) ssl).getServerSocketFactory();
138    }
139
140    protected final RuntimeException buildRuntimeException(Exception cause) {
141        return new RuntimeException(cause);
142    }
143
144    protected final SSLSocket buildSocket(SSL ssl) throws IOException {
145        SSLSocketFactory sf = ssl.getSSLSocketFactory();
146        SSLSocket s = (SSLSocket) sf.createSocket();
147        ssl.doPreConnectSocketStuff(s);
148        return s;
149    }
150
151    protected final SSLSocket buildSocket(SSL ssl, String remoteHost,
152                                          int remotePort, InetAddress localHost,
153                                          int localPort, int timeout)
154        throws IOException {
155        SSLSocket s = buildSocket(ssl);
156        s = (SSLSocket) connectSocket(s, null, remoteHost, remotePort,
157            localHost, localPort, timeout, ssl);
158        ssl.doPostConnectSocketStuff(s, remoteHost);
159        return s;
160    }
161
162
163    protected final Socket buildPlainSocket(
164            SSL ssl, String remoteHost, int remotePort, InetAddress localHost, int localPort, int timeout
165    ) throws IOException {
166        Socket s = SocketFactory.getDefault().createSocket();
167        ssl.doPreConnectSocketStuff(s);
168        s = connectSocket(
169                s, null, remoteHost, remotePort, localHost, localPort, timeout, ssl
170        );
171        ssl.doPostConnectSocketStuff(s, remoteHost);
172        return s;
173    }
174
175    protected final Socket connectSocket(Socket s, SocketFactory sf,
176                                         String host, int remotePort,
177                                         InetAddress localHost, int localPort,
178                                         int timeout, SSL ssl)
179        throws IOException {
180        if (s == null) {
181            if (sf == null) {
182                s = new Socket();
183            } else {
184                s = sf.createSocket();
185            }
186        }
187        host = ssl.dnsOverride(host);
188        InetAddress remoteHost = Util.toInetAddress(host);
189        InetSocketAddress dest = new InetSocketAddress(remoteHost, remotePort);
190        InetSocketAddress src = new InetSocketAddress(localHost, localPort);
191        if (s instanceof SSLSocket) {
192            setHostForSNI((SSLSocket) s, host);
193        }
194        s.bind(src);
195        s.connect(dest, timeout);
196        return s;
197    }
198
199    private static boolean returnsVoidTakesOneString(Method m) {
200        Class<?>[] params = m.getParameterTypes();
201        return Void.TYPE.equals(m.getReturnType())
202                && params != null && params.length == 1 && String.class.equals(params[0]);
203    }
204
205    public static void setHostForSNI(SSLSocket s, String host) throws IOException {
206        // Tries to call a "setHost()" method on the supplied SSLSocket via reflection if one exists.
207        Method[] methods = s.getClass().getMethods();
208        for (int i = 0; i < methods.length; i++) {
209            Method m = methods[i];
210            if (returnsVoidTakesOneString(m) && "setHost".equals(m.getName())) {
211                try {
212
213                    m.invoke(s, host);
214                    return;
215
216                } catch (IllegalAccessException iae) {
217
218                    // oh well, nevermind
219
220                } catch (InvocationTargetException ite) {
221                    Throwable t = ite.getCause();
222                    if (t instanceof IOException) {
223                        throw (IOException) t;
224                    } else if (t instanceof RuntimeException) {
225                        throw (RuntimeException) t;
226                    } else if (t instanceof Error) {
227                        throw (Error) t;
228                    } else {
229                        throw new IOException("setHost() via reflection failed: " + t);
230                    }
231                }
232            }
233        }
234    }
235
236    protected final SSLServerSocket buildServerSocket(SSL ssl)
237        throws IOException {
238        ServerSocket s = ssl.getSSLServerSocketFactory().createServerSocket();
239        SSLServerSocket ss = (SSLServerSocket) s;
240        ssl.doPreConnectServerSocketStuff(ss);
241        return ss;
242    }
243
244    protected final void wantClientAuth(Object o, boolean wantClientAuth) {
245        SSLSocket s;
246        SSLServerSocket ss;
247        if (o instanceof SSLSocket) {
248            s = (SSLSocket) o;
249            s.setWantClientAuth(wantClientAuth);
250        } else if (o instanceof SSLServerSocket) {
251            ss = (SSLServerSocket) o;
252            ss.setWantClientAuth(wantClientAuth);
253        } else {
254            throw new ClassCastException("need SSLSocket or SSLServerSocket");
255        }
256    }
257
258    protected final void enabledProtocols(Object o, String[] enabledProtocols) {
259        SSLSocket s;
260        SSLServerSocket ss;
261        if (o instanceof SSLSocket) {
262            s = (SSLSocket) o;
263            s.setEnabledProtocols(enabledProtocols);
264        } else if (o instanceof SSLServerSocket) {
265            ss = (SSLServerSocket) o;
266            ss.setEnabledProtocols(enabledProtocols);
267        } else {
268            throw new ClassCastException("need SSLSocket or SSLServerSocket");
269        }
270    }
271
272    protected void checkTrusted(Object trustManager, X509Certificate[] chain,
273                                String authType)
274        throws CertificateException {
275        X509TrustManager tm = (X509TrustManager) trustManager;
276        tm.checkServerTrusted(chain, authType);
277    }
278
279    protected final Object initSSL(SSL ssl, TrustChain tc, KeyMaterial k)
280        throws NoSuchAlgorithmException, KeyStoreException,
281        CertificateException, KeyManagementException, IOException {
282        SSLContext context = SSLContext.getInstance(ssl.getDefaultProtocol());
283        TrustManager[] trustManagers = null;
284        KeyManager[] keyManagers = null;
285        if (tc != null) {
286            trustManagers = (TrustManager[]) tc.getTrustManagers();
287        }
288        if (k != null) {
289            keyManagers = (KeyManager[]) k.getKeyManagers();
290        }
291        if (keyManagers != null) {
292            for (int i = 0; i < keyManagers.length; i++) {
293                if (keyManagers[i] instanceof X509KeyManager) {
294                    X509KeyManager km = (X509KeyManager) keyManagers[i];
295                    keyManagers[i] = new Java14KeyManagerWrapper(km, k, ssl);
296                }
297            }
298        }
299        if (trustManagers != null) {
300            for (int i = 0; i < trustManagers.length; i++) {
301                if (trustManagers[i] instanceof X509TrustManager) {
302                    X509TrustManager tm = (X509TrustManager) trustManagers[i];
303                    trustManagers[i] = new Java14TrustManagerWrapper(tm, tc, ssl);
304                }
305            }
306        }
307        context.init(keyManagers, trustManagers, null);
308        return context;
309    }
310
311
312}