diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java index 5ee40186f..791ccd5ec 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java @@ -1,5 +1,8 @@ package de.danoeh.antennapod.core.gpoddernet; +import android.os.Build; +import android.util.Log; + import com.squareup.okhttp.Credentials; import com.squareup.okhttp.MediaType; import com.squareup.okhttp.OkHttpClient; @@ -18,16 +21,27 @@ import org.json.JSONObject; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.CookieManager; -import java.net.CookiePolicy; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.security.KeyStore; +import java.security.Principal; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; +import javax.security.auth.x500.X500Principal; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.gpoddernet.model.GpodnetDevice; @@ -43,6 +57,8 @@ import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; */ public class GpodnetService { + private static final String TAG = "GpodnetService"; + private static final String BASE_SCHEME = "https"; public static final String DEFAULT_BASE_HOST = "gpodder.net"; @@ -56,9 +72,84 @@ public class GpodnetService { public GpodnetService() { httpClient = AntennapodHttpClient.getHttpClient(); + if (Build.VERSION.SDK_INT <= 10) { + Log.d(TAG, "Use custom SSL factory"); + SSLSocketFactory factory = getCustomSslSocketFactory(); + httpClient.setSslSocketFactory(factory); + } BASE_HOST = GpodnetPreferences.getHostname(); } + private synchronized static SSLSocketFactory getCustomSslSocketFactory() { + try { + TrustManagerFactory defaultTrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + defaultTrustManagerFactory.init((KeyStore) null); // use system keystore + final X509TrustManager defaultTrustManager = (X509TrustManager) defaultTrustManagerFactory.getTrustManagers()[0]; + TrustManager[] customTrustManagers = new TrustManager[]{new X509TrustManager() { + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + } + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + // chain may out of order - construct data structures to walk from server certificate to root certificate + Map certificates = new HashMap(chain.length - 1); + X509Certificate subject = null; + for (X509Certificate cert : chain) { + cert.checkValidity(); + if (cert.getSubjectDN().toString().startsWith("CN=" + DEFAULT_BASE_HOST)) { + subject = cert; + } else { + certificates.put(cert.getSubjectDN(), cert); + } + } + if (subject == null) { + throw new CertificateException("Chain does not contain a certificate for " + DEFAULT_BASE_HOST); + } + // follow chain to root CA + while (certificates.get(subject.getIssuerDN()) != null) { + subject.checkValidity(); + X509Certificate issuer = certificates.get(subject.getIssuerDN()); + try { + subject.verify(issuer.getPublicKey()); + } catch (Exception e) { + Log.d(TAG, "failed: " + issuer.getSubjectDN() + " -> " + subject.getSubjectDN()); + throw new CertificateException("Could not verify certificate"); + } + subject = issuer; + } + X500Principal rootAuthority = subject.getIssuerX500Principal(); + boolean accepted = false; + for (X509Certificate cert : + defaultTrustManager.getAcceptedIssuers()) { + if (cert.getSubjectX500Principal().equals(rootAuthority)) { + try { + subject.verify(cert.getPublicKey()); + accepted = true; + } catch (Exception e) { + Log.d(TAG, "failed: " + cert.getSubjectDN() + " -> " + subject.getSubjectDN()); + throw new CertificateException("Could not verify root certificate"); + } + } + } + if (accepted == false) { + throw new CertificateException("Could not verify root certificate"); + } + } + }}; + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, customTrustManagers, null); + return sslContext.getSocketFactory(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + /** * Returns the [count] most used tags. */