diff --git a/.gitmodules b/.gitmodules index ca1aa6458..eeaf305bc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,9 @@ path = extern/Universal-Image-Loader url = https://github.com/nostra13/Android-Universal-Image-Loader ignore = dirty +[submodule "extern/MemorizingTrustManager"] + path = extern/MemorizingTrustManager + url = https://github.com/ge0rg/MemorizingTrustManager.git +[submodule "extern/AndroidPinning"] + path = extern/AndroidPinning + url = https://github.com/binaryparadox/AndroidPinning.git diff --git a/AndroidManifest.xml b/AndroidManifest.xml index e6366d4ca..0118acdf9 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -200,6 +200,9 @@ android:name="android.app.searchable" android:resource="@xml/searchable" /> + + + diff --git a/README.md b/README.md index 718c54b73..cf4b657a3 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,10 @@ The only required tools are the Android SDK and Apache Ant. ``` git submodule update --init -android update project -p . -android update project -p extern/Universal-Image-Loader/library +android update project -p . --name F-droid +android update lib-project -p extern/Universal-Image-Loader/library +android update lib-project -p extern/AndroidPinning +android update lib-project -p extern/MemorizingTrustManager ant clean release ``` diff --git a/extern/AndroidPinning b/extern/AndroidPinning new file mode 160000 index 000000000..526654e1b --- /dev/null +++ b/extern/AndroidPinning @@ -0,0 +1 @@ +Subproject commit 526654e1b9997b32e513d58d9094d4c1102a6cb3 diff --git a/extern/MemorizingTrustManager b/extern/MemorizingTrustManager new file mode 160000 index 000000000..49452f67a --- /dev/null +++ b/extern/MemorizingTrustManager @@ -0,0 +1 @@ +Subproject commit 49452f67a760dfef77ddaa7e0b7d88c713c4a195 diff --git a/project.properties b/project.properties index 9d03d0bbe..6da907dd2 100644 --- a/project.properties +++ b/project.properties @@ -3,3 +3,5 @@ proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project. target=android-19 android.library.reference.1=extern/Universal-Image-Loader/library +android.library.reference.2=extern/MemorizingTrustManager +android.library.reference.3=extern/AndroidPinning diff --git a/src/org/fdroid/fdroid/FDroidApp.java b/src/org/fdroid/fdroid/FDroidApp.java index 7523c5245..0558d1f25 100644 --- a/src/org/fdroid/fdroid/FDroidApp.java +++ b/src/org/fdroid/fdroid/FDroidApp.java @@ -19,26 +19,45 @@ package org.fdroid.fdroid; import java.io.File; -import java.lang.Runtime; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Semaphore; -import android.app.Application; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + import android.app.Activity; -import android.preference.PreferenceManager; -import android.util.Log; +import android.app.Application; import android.content.Context; import android.content.SharedPreferences; import org.fdroid.fdroid.Utils; +import android.graphics.Bitmap; +import android.preference.PreferenceManager; +import android.util.Log; + import com.nostra13.universalimageloader.cache.disc.impl.LimitedAgeDiscCache; +import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache; import com.nostra13.universalimageloader.cache.disc.naming.FileNameGenerator; +import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; +import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer; import com.nostra13.universalimageloader.utils.StorageUtils; +import de.duenndns.ssl.MemorizingTrustManager; + +import org.thoughtcrime.ssl.pinning.PinningTrustManager; +import org.thoughtcrime.ssl.pinning.SystemKeyStore; + public class FDroidApp extends Application { private static enum Theme { @@ -117,6 +136,44 @@ public class FDroidApp extends Application { .threadPoolSize(Runtime.getRuntime().availableProcessors() * 2) .build(); ImageLoader.getInstance().init(config); + + try { + SSLContext sc = SSLContext.getInstance("TLS"); + X509TrustManager defaultTrustManager = null; + + /* + * init a trust manager factory with a null keystore to access the system trust managers + */ + TrustManagerFactory tmf = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + KeyStore ks = null; + tmf.init(ks); + TrustManager[] mgrs = tmf.getTrustManagers(); + + if(mgrs.length > 0 && mgrs[0] instanceof X509TrustManager) + defaultTrustManager = (X509TrustManager) mgrs[0]; + + /* + * compose a chain of trust managers as follows: + * MemorizingTrustManager -> Pinning Trust Manager -> System Trust Manager + */ + PinningTrustManager pinMgr = new PinningTrustManager(SystemKeyStore.getInstance(ctx),FDroidCertPins.getPinList(), 0); + MemorizingTrustManager memMgr = new MemorizingTrustManager(ctx, pinMgr, defaultTrustManager); + + /* + * initialize a SSLContext with the outermost trust manager, use this + * context to set the default SSL socket factory for the HTTPSURLConnection + * class. + */ + sc.init(null, new TrustManager[] {memMgr}, new java.security.SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); + } catch (KeyManagementException e) { + Log.e("FDroid", "Unable to set up trust manager chain. KeyManagementException"); + } catch (NoSuchAlgorithmException e) { + Log.e("FDroid", "Unable to set up trust manager chain. NoSuchAlgorithmException"); + } catch (KeyStoreException e) { + Log.e("FDroid", "Unable to set up trust manager chain. KeyStoreException"); + } } private Context ctx; diff --git a/src/org/fdroid/fdroid/FDroidCertPins.java b/src/org/fdroid/fdroid/FDroidCertPins.java new file mode 100644 index 000000000..09627a0fc --- /dev/null +++ b/src/org/fdroid/fdroid/FDroidCertPins.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010-12 Ciaran Gultnieks, ciaran@ciarang.com + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.fdroid.fdroid; + +import java.util.ArrayList; +import java.util.Arrays; + +public class FDroidCertPins { + public static final String[] DEFAULT_PINS = + { + /* + * SubjectDN: CN=f-droid.org, OU=PositiveSSL, OU=Domain Control Validated + * IssuerDN: CN=PositiveSSL CA 2, O=COMODO CA Limited, L=Salford, ST=Greater Manchester, C=GB + * Fingerprint: 84B91CDF2312CB9BA7F3BE803783302F8D8C299F + * SPKI Pin: 638F93856E1F5EDFCBD40C46D4160CFF21B0713A + */ + "638F93856E1F5EDFCBD40C46D4160CFF21B0713A", + + /* + * SubjectDN: CN=guardianproject.info, OU=Gandi Standard SSL, OU=Domain Control Validated + * IssuerDN: CN=Gandi Standard SSL CA, O=GANDI SAS, C=FR + * Fingerprint: 187C2573E924DFCBFF2A781A2F99D71C6E031828 + * SPKI Pin: EB6BBC6C6BAEEA20CB0F3357720D86E0F3A526F4 + */ + "EB6BBC6C6BAEEA20CB0F3357720D86E0F3A526F4", + }; + + public static ArrayList PINLIST = null; + + public static String[] getPinList() + { + if(PINLIST == null) + { + PINLIST = new ArrayList(); + PINLIST.addAll(Arrays.asList(DEFAULT_PINS)); + } + + return PINLIST.toArray(new String[PINLIST.size()]); + } +}