+++ /dev/null
-/* ownCloud Android client application
- * Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2012-2013 ownCloud Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package com.owncloud.android.network;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.UnknownHostException;
-import java.security.cert.X509Certificate;
-
-import javax.net.SocketFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocket;
-
-import org.apache.commons.httpclient.ConnectTimeoutException;
-import org.apache.commons.httpclient.params.HttpConnectionParams;
-import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
-import org.apache.http.conn.ssl.X509HostnameVerifier;
-
-import android.util.Log;
-
-/**
- * AdvancedSSLProtocolSocketFactory allows to create SSL {@link Socket}s with
- * a custom SSLContext and an optional Hostname Verifier.
- *
- * @author David A. Velasco
- */
-
-public class AdvancedSslSocketFactory implements ProtocolSocketFactory {
-
- private static final String TAG = AdvancedSslSocketFactory.class.getSimpleName();
-
- private SSLContext mSslContext = null;
- private AdvancedX509TrustManager mTrustManager = null;
- private X509HostnameVerifier mHostnameVerifier = null;
-
- public SSLContext getSslContext() {
- return mSslContext;
- }
-
- /**
- * Constructor for AdvancedSSLProtocolSocketFactory.
- */
- public AdvancedSslSocketFactory(SSLContext sslContext, AdvancedX509TrustManager trustManager, X509HostnameVerifier hostnameVerifier) {
- if (sslContext == null)
- throw new IllegalArgumentException("AdvancedSslSocketFactory can not be created with a null SSLContext");
- if (trustManager == null)
- throw new IllegalArgumentException("AdvancedSslSocketFactory can not be created with a null Trust Manager");
- mSslContext = sslContext;
- mTrustManager = trustManager;
- mHostnameVerifier = hostnameVerifier;
- }
-
- /**
- * @see ProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int)
- */
- public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException, UnknownHostException {
- Socket socket = mSslContext.getSocketFactory().createSocket(host, port, clientHost, clientPort);
- verifyPeerIdentity(host, port, socket);
- return socket;
- }
-
-
- /**
- * Attempts to get a new socket connection to the given host within the
- * given time limit.
- *
- * @param host the host name/IP
- * @param port the port on the host
- * @param clientHost the local host name/IP to bind the socket to
- * @param clientPort the port on the local machine
- * @param params {@link HttpConnectionParams Http connection parameters}
- *
- * @return Socket a new socket
- *
- * @throws IOException if an I/O error occurs while creating the socket
- * @throws UnknownHostException if the IP address of the host cannot be
- * determined
- */
- public Socket createSocket(final String host, final int port,
- final InetAddress localAddress, final int localPort,
- final HttpConnectionParams params) throws IOException,
- UnknownHostException, ConnectTimeoutException {
- Log.d(TAG, "Creating SSL Socket with remote " + host + ":" + port + ", local " + localAddress + ":" + localPort + ", params: " + params);
- if (params == null) {
- throw new IllegalArgumentException("Parameters may not be null");
- }
- int timeout = params.getConnectionTimeout();
- SocketFactory socketfactory = mSslContext.getSocketFactory();
- Log.d(TAG, " ... with connection timeout " + timeout + " and socket timeout " + params.getSoTimeout());
- Socket socket = socketfactory.createSocket();
- SocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
- SocketAddress remoteaddr = new InetSocketAddress(host, port);
- socket.setSoTimeout(params.getSoTimeout());
- socket.bind(localaddr);
- socket.connect(remoteaddr, timeout);
- verifyPeerIdentity(host, port, socket);
- return socket;
- }
-
- /**
- * @see ProtocolSocketFactory#createSocket(java.lang.String,int)
- */
- public Socket createSocket(String host, int port) throws IOException,
- UnknownHostException {
- Log.d(TAG, "Creating SSL Socket with remote " + host + ":" + port);
- Socket socket = mSslContext.getSocketFactory().createSocket(host, port);
- verifyPeerIdentity(host, port, socket);
- return socket;
- }
-
- public boolean equals(Object obj) {
- return ((obj != null) && obj.getClass().equals(
- AdvancedSslSocketFactory.class));
- }
-
- public int hashCode() {
- return AdvancedSslSocketFactory.class.hashCode();
- }
-
-
- public X509HostnameVerifier getHostNameVerifier() {
- return mHostnameVerifier;
- }
-
-
- public void setHostNameVerifier(X509HostnameVerifier hostnameVerifier) {
- mHostnameVerifier = hostnameVerifier;
- }
-
- /**
- * Verifies the identity of the server.
- *
- * The server certificate is verified first.
- *
- * Then, the host name is compared with the content of the server certificate using the current host name verifier, if any.
- * @param socket
- */
- private void verifyPeerIdentity(String host, int port, Socket socket) throws IOException {
- try {
- CertificateCombinedException failInHandshake = null;
- /// 1. VERIFY THE SERVER CERTIFICATE through the registered TrustManager (that should be an instance of AdvancedX509TrustManager)
- try {
- SSLSocket sock = (SSLSocket) socket; // a new SSLSession instance is created as a "side effect"
- sock.startHandshake();
-
- } catch (RuntimeException e) {
-
- if (e instanceof CertificateCombinedException) {
- failInHandshake = (CertificateCombinedException) e;
- } else {
- Throwable cause = e.getCause();
- Throwable previousCause = null;
- while (cause != null && cause != previousCause && !(cause instanceof CertificateCombinedException)) {
- previousCause = cause;
- cause = cause.getCause();
- }
- if (cause != null && cause instanceof CertificateCombinedException) {
- failInHandshake = (CertificateCombinedException)cause;
- }
- }
- if (failInHandshake == null) {
- throw e;
- }
- failInHandshake.setHostInUrl(host);
-
- }
-
- /// 2. VERIFY HOSTNAME
- SSLSession newSession = null;
- boolean verifiedHostname = true;
- if (mHostnameVerifier != null) {
- if (failInHandshake != null) {
- /// 2.1 : a new SSLSession instance was NOT created in the handshake
- X509Certificate serverCert = failInHandshake.getServerCertificate();
- try {
- mHostnameVerifier.verify(host, serverCert);
- } catch (SSLException e) {
- verifiedHostname = false;
- }
-
- } else {
- /// 2.2 : a new SSLSession instance was created in the handshake
- newSession = ((SSLSocket)socket).getSession();
- if (!mTrustManager.isKnownServer((X509Certificate)(newSession.getPeerCertificates()[0]))) {
- verifiedHostname = mHostnameVerifier.verify(host, newSession);
- }
- }
- }
-
- /// 3. Combine the exceptions to throw, if any
- if (!verifiedHostname) {
- SSLPeerUnverifiedException pue = new SSLPeerUnverifiedException("Names in the server certificate do not match to " + host + " in the URL");
- if (failInHandshake == null) {
- failInHandshake = new CertificateCombinedException((X509Certificate) newSession.getPeerCertificates()[0]);
- failInHandshake.setHostInUrl(host);
- }
- failInHandshake.setSslPeerUnverifiedException(pue);
- pue.initCause(failInHandshake);
- throw pue;
-
- } else if (failInHandshake != null) {
- SSLHandshakeException hse = new SSLHandshakeException("Server certificate could not be verified");
- hse.initCause(failInHandshake);
- throw hse;
- }
-
- } catch (IOException io) {
- try {
- socket.close();
- } catch (Exception x) {
- // NOTHING - irrelevant exception for the caller
- }
- throw io;
- }
- }
-
-}