Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2799b3e8 authored by jabarros's avatar jabarros
Browse files

Merge pull request #43 from owncloud/tls_v1.1_and_v1.2_support

TLS v1.1 and v1.2 support, plus test project refactored to use "same" socket factory as library
parents 4f315c7e a5a2b289
Loading
Loading
Loading
Loading
+38 −9
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
@@ -78,8 +79,11 @@ public class AdvancedSslSocketFactory implements SecureProtocolSocketFactory {
    	
        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");
        if (trustManager == null && mHostnameVerifier != null)
            throw new IllegalArgumentException(
            		"AdvancedSslSocketFactory can not be created with a null Trust Manager and a " +
            		"not null Hostname Verifier"
    		);
        mSslContext = sslContext;
        mTrustManager = trustManager;
        mHostnameVerifier = hostnameVerifier;
@@ -92,6 +96,7 @@ public class AdvancedSslSocketFactory implements SecureProtocolSocketFactory {
    		throws IOException, UnknownHostException {
    	
        Socket socket = mSslContext.getSocketFactory().createSocket(host, port, clientHost, clientPort);
        enableSecureProtocols(socket);
        verifyPeerIdentity(host, port, socket);
        return socket;
    }
@@ -168,6 +173,7 @@ public class AdvancedSslSocketFactory implements SecureProtocolSocketFactory {
        SocketFactory socketfactory = mSslContext.getSocketFactory();
        Log_OC.d(TAG, " ... with connection timeout " + timeout + " and socket timeout " + params.getSoTimeout());
        Socket socket = socketfactory.createSocket();
        enableSecureProtocols(socket);
        SocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
        SocketAddress remoteaddr = new InetSocketAddress(host, port);
        socket.setSoTimeout(params.getSoTimeout());
@@ -185,10 +191,22 @@ public class AdvancedSslSocketFactory implements SecureProtocolSocketFactory {
            UnknownHostException {
    	Log_OC.d(TAG, "Creating SSL Socket with remote " + host + ":" + port);
        Socket socket = mSslContext.getSocketFactory().createSocket(host, port);
        enableSecureProtocols(socket);
        verifyPeerIdentity(host, port, socket);
        return socket; 
    }

    
	@Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException,
    		UnknownHostException {
	    Socket sslSocket = mSslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
	    enableSecureProtocols(sslSocket);
	    verifyPeerIdentity(host, port, sslSocket);
	    return sslSocket;
	}

    
    public boolean equals(Object obj) {
        return ((obj != null) && obj.getClass().equals(
                AdvancedSslSocketFactory.class));
@@ -303,11 +321,22 @@ public class AdvancedSslSocketFactory implements SecureProtocolSocketFactory {
        }
    }

	@Override
	public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException,
			UnknownHostException {
		Socket sslSocket = mSslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
		verifyPeerIdentity(host, port, sslSocket);
		return sslSocket;
	/**
	 * Grants that all protocols supported by the Security Provider in mSslContext are enabled in socket.
	 * 
	 * Grants also that no unsupported protocol is tried to be enabled. That would trigger an exception, breaking
	 * the connection process although some protocols are supported.
	 * 
	 * This is not cosmetic: not all the supported protocols are enabled by default. Too see an overview of 
	 * supported and enabled protocols in the stock Security Provider in Android see the tables in
	 * http://developer.android.com/reference/javax/net/ssl/SSLSocket.html.
	 *  
	 * @param socket
	 */
    private void enableSecureProtocols(Socket socket) {
    	SSLParameters params = mSslContext.getSupportedSSLParameters();
    	String [] supportedProtocols = params.getProtocols();
    	((SSLSocket) socket).setEnabledProtocols(supportedProtocols);
    }
	
}
+31 −9
Original line number Diff line number Diff line
@@ -58,6 +58,12 @@ public class NetworkUtils {
    /** Default timeout for establishing a connection */
    public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
    
    /** Standard name for protocol TLS version 1.2 in Java Secure Socket Extension (JSSE) API */
    public static final String PROTOCOL_TLSv1_2 = "TLSv1.2";
    
    /** Standard name for protocol TLS version 1.0 in JSSE API */
    public static final String PROTOCOL_TLSv1_0 = "TLSv1";

    /** Connection manager for all the OwnCloudClients */
    private static MultiThreadedHttpConnectionManager mConnManager = null;
    
@@ -72,7 +78,9 @@ public class NetworkUtils {
     * Registers or unregisters the proper components for advanced SSL handling.
     * @throws IOException 
     */
    public static void registerAdvancedSslContext(boolean register, Context context) throws GeneralSecurityException, IOException {
    @SuppressWarnings("deprecation")
	public static void registerAdvancedSslContext(boolean register, Context context) 
    		throws GeneralSecurityException, IOException {
        Protocol pr = null;
        try {
            pr = Protocol.getProtocol("https");
@@ -93,13 +101,22 @@ public class NetworkUtils {
        }
    }
    
    public static AdvancedSslSocketFactory getAdvancedSslSocketFactory(Context context) throws GeneralSecurityException, IOException {
    public static AdvancedSslSocketFactory getAdvancedSslSocketFactory(Context context) 
    		throws GeneralSecurityException, IOException {
        if (mAdvancedSslSocketFactory  == null) {
            KeyStore trustStore = getKnownServersStore(context);
            AdvancedX509TrustManager trustMgr = new AdvancedX509TrustManager(trustStore);
            TrustManager[] tms = new TrustManager[] { trustMgr };
                
            SSLContext sslContext = SSLContext.getInstance("TLS");
            SSLContext sslContext;
            try {
            	sslContext = SSLContext.getInstance("TLSv1.2");
            } catch (NoSuchAlgorithmException e) {
            	Log_OC.w(TAG, "TLSv1.2 is not supported in this device; falling through TLSv1.0");
            	sslContext = SSLContext.getInstance("TLSv1");
            	// should be available in any device; see reference of supported protocols in 
            	// http://developer.android.com/reference/javax/net/ssl/SSLSocket.html
            }
            sslContext.init(null, tms, null);
                    
            mHostnameVerifier = new BrowserCompatHostnameVerifier();
@@ -127,9 +144,11 @@ public class NetworkUtils {
     * @throws KeyStoreException            When the KeyStore instance could not be created.
     * @throws IOException                  When an existing local trust store could not be loaded.
     * @throws NoSuchAlgorithmException     When the existing local trust store was saved with an unsupported algorithm.
     * @throws CertificateException         When an exception occurred while loading the certificates from the local trust store.
     * @throws CertificateException         When an exception occurred while loading the certificates from the local 
     * 										trust store.
     */
    private static KeyStore getKnownServersStore(Context context) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
    private static KeyStore getKnownServersStore(Context context) 
    		throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
        if (mKnownServersStore == null) {
            //mKnownServersStore = KeyStore.getInstance("BKS");
            mKnownServersStore = KeyStore.getInstance(KeyStore.getDefaultType());
@@ -143,15 +162,17 @@ public class NetworkUtils {
                    in.close();
                }
            } else {
                mKnownServersStore.load(null, LOCAL_TRUSTSTORE_PASSWORD.toCharArray()); // necessary to initialize an empty KeyStore instance
            	// next is necessary to initialize an empty KeyStore instance
            	mKnownServersStore.load(null, LOCAL_TRUSTSTORE_PASSWORD.toCharArray()); 
            }
        }
        return mKnownServersStore;
    }
    
    
    public static void addCertToKnownServersStore(Certificate cert, Context context) throws  KeyStoreException, NoSuchAlgorithmException, 
                                                                                            CertificateException, IOException {
    public static void addCertToKnownServersStore(Certificate cert, Context context) 
    		throws  KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
    	
        KeyStore knownServers = getKnownServersStore(context);
        knownServers.setCertificateEntry(Integer.toString(cert.hashCode()), cert);
        FileOutputStream fos = null;
@@ -173,7 +194,8 @@ public class NetworkUtils {
        return mConnManager;
    }

    public static boolean isCertInKnownServersStore(Certificate cert, Context context) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
    public static boolean isCertInKnownServersStore(Certificate cert, Context context) 
    		throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
    	
    	KeyStore knownServers = getKnownServersStore(context);
    	Log_OC.d(TAG, "Certificate - HashCode: " + cert.hashCode() + " "
+14 −0
Original line number Diff line number Diff line
@@ -43,5 +43,19 @@
				byline="true" />
			</then>
		</if>
		
		<!-- Make Travis build number available to the test app in the emulator -->
		<if>
			<condition>
				<isset property="env.TRAVIS_BUILD_NUMBER" />
			</condition>
			<then>
				<replaceregexp
				file="res/values/setup.xml"
				match='("build_number"&gt;)\s*(&lt;)'
				replace="\1${env.TRAVIS_BUILD_NUMBER}\2"
				byline="true" />
			</then>
		</if>
	</target>
</project>
 No newline at end of file
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
 -->
 
<resources>
    <string name="build_number"></string>
    <string name="server_base_url"></string>
    <string name="username"></string>
    <string name="password"></string>
+14 −33
Original line number Diff line number Diff line
@@ -26,9 +26,7 @@ package com.owncloud.android.lib.test_project;

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.GeneralSecurityException;
import java.security.KeyStore;
@@ -38,9 +36,7 @@ import java.security.cert.CertStoreException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
@@ -49,7 +45,7 @@ import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;

import com.owncloud.android.lib.common.network.ServerNameIndicator;
import com.owncloud.android.lib.common.network.AdvancedSslSocketFactory;


/**
@@ -64,7 +60,8 @@ import com.owncloud.android.lib.common.network.ServerNameIndicator;
public class SelfSignedConfidentSslSocketFactory implements SecureProtocolSocketFactory {

	
	private SSLContext mSslContext = null;
	//private SSLContext mSslContext = null;
	private AdvancedSslSocketFactory mWrappedSslSocketFactory = null;
	
	
	/**
@@ -72,7 +69,13 @@ public class SelfSignedConfidentSslSocketFactory implements SecureProtocolSocket
	 * @throws GeneralSecurityException 
	 */
	public SelfSignedConfidentSslSocketFactory() throws GeneralSecurityException {
		mSslContext = createSslContext();
		SSLContext sslContext = SSLContext.getInstance("TLS");
		sslContext.init(
				null, 
				new TrustManager[] { new SelfSignedConfidentX509TrustManager() }, 
				null
		);
        mWrappedSslSocketFactory = new AdvancedSslSocketFactory(sslContext, null, null);		
	}

	
@@ -81,7 +84,7 @@ public class SelfSignedConfidentSslSocketFactory implements SecureProtocolSocket
	 */
	@Override
	public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
		return mSslContext.getSocketFactory().createSocket(host, port);
		return mWrappedSslSocketFactory.createSocket(host, port);
	}
	
	/**
@@ -90,7 +93,7 @@ public class SelfSignedConfidentSslSocketFactory implements SecureProtocolSocket
	@Override
	public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort)
			throws IOException, UnknownHostException {
		return mSslContext.getSocketFactory().createSocket(host, port, clientHost, clientPort);
		return mWrappedSslSocketFactory.createSocket(host, port, clientHost, clientPort);
	}
	
	/**
@@ -112,19 +115,7 @@ public class SelfSignedConfidentSslSocketFactory implements SecureProtocolSocket
			HttpConnectionParams params) throws IOException, UnknownHostException,
			ConnectTimeoutException {
		
		if (params == null) {
			throw new IllegalArgumentException("Parameters may not be null");
		}
		int timeout = params.getConnectionTimeout();
		SocketFactory socketfactory = mSslContext.getSocketFactory();
		Socket socket = socketfactory.createSocket();
		SocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
		SocketAddress remoteaddr = new InetSocketAddress(host, port);
		socket.setSoTimeout(params.getSoTimeout());
		socket.bind(localaddr);
		ServerNameIndicator.setServerNameIndication(host, (SSLSocket)socket);
		socket.connect(remoteaddr, timeout);
		return socket;
		return mWrappedSslSocketFactory.createSocket(host, port, localAddress, localPort, params);
	}

	/**
@@ -133,20 +124,10 @@ public class SelfSignedConfidentSslSocketFactory implements SecureProtocolSocket
	@Override
	public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
			throws IOException, UnknownHostException {
		return mSslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
		return mWrappedSslSocketFactory.createSocket(socket, host, port, autoClose);
	}
	
	
	
	private static SSLContext createSslContext() throws GeneralSecurityException {
		SSLContext context = SSLContext.getInstance("TLS");
		context.init(
				null, 
				new TrustManager[] {new SelfSignedConfidentX509TrustManager()}, 
				null);
		return context;
	}	
	
	public static class SelfSignedConfidentX509TrustManager implements X509TrustManager {

	    private X509TrustManager mStandardTrustManager = null;
Loading