/* DroidBeard - a free, open-source Android app for managing SickBeard Copyright (C) 2014-2015 Robert Carr 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 3 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.rastating.droidbeard.net; import android.net.SSLCertificateSocketFactory; import android.util.Log; import org.apache.http.conn.scheme.LayeredSocketFactory; import org.apache.http.conn.ssl.StrictHostnameVerifier; import org.apache.http.params.HttpParams; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; public class TlsSocketFactory implements LayeredSocketFactory { final static HostnameVerifier hostnameVerifier = new StrictHostnameVerifier(); private boolean mTrustAllCertificates; public TlsSocketFactory(boolean trustAllCertificates) { mTrustAllCertificates = trustAllCertificates; } @Override public Socket connectSocket(Socket s, String host, int port, InetAddress localAddress, int localPort, HttpParams params) throws IOException { return null; } @Override public Socket createSocket() throws IOException { return null; } @Override public boolean isSecure(Socket s) throws IllegalArgumentException { return s instanceof SSLSocket && ((SSLSocket) s).isConnected(); } @Override public Socket createSocket(Socket plainSocket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { // Create and connect SSL socket, but don't do hostname/certificate verification yet SSLCertificateSocketFactory sslSocketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(0); // Setup custom trust manager if we are trusting all certificates if (mTrustAllCertificates) { TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; sslSocketFactory.setTrustManagers(new TrustManager[] { tm }); } SSLSocket ssl = (SSLSocket)sslSocketFactory.createSocket(InetAddress.getByName(host), port); // Enable TLSv1.1/1.2 if available // (see https://github.com/rfc2822/davdroid/issues/229) ssl.setEnabledProtocols(ssl.getSupportedProtocols()); SSLSession session = ssl.getSession(); // Verify hostname and certificate if we aren't trusting all certificates if (!mTrustAllCertificates) { if (!hostnameVerifier.verify(host, session)) throw new SSLPeerUnverifiedException("Cannot verify hostname: " + host); } Log.i("droidbeard", "Established " + session.getProtocol() + " connection with " + session.getPeerHost() + " using " + session.getCipherSuite()); return ssl; } }