diff --git a/app/src/main/assets/cert/purplei2p.crt b/app/src/main/assets/cert/purplei2p.crt new file mode 100644 index 0000000..bbbcc77 --- /dev/null +++ b/app/src/main/assets/cert/purplei2p.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID7DCCAtSgAwIBAgIJAKXaTovgoTIUMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJXVzEUMBIGA1UECAwLSTJQIE5ldHdvcmsxEjAQBgNVBAoMCVB1cnBsZUky +UDEqMCgGA1UEAwwhUHVycGxlSTJQIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR0w +GwYJKoZIhvcNAQkBFg5yNHNhc0BtYWlsLmkycDAeFw0xODA4MjQyMTQ3NTJaFw0y +MzA4MjMyMTQ3NTJaMIGCMQswCQYDVQQGEwJXVzEUMBIGA1UECAwLSTJQIE5ldHdv +cmsxEjAQBgNVBAoMCVB1cnBsZUkyUDEqMCgGA1UEAwwhUHVycGxlSTJQIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MR0wGwYJKoZIhvcNAQkBFg5yNHNhc0BtYWlsLmky +cDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALAZnN/U5bgkmiBqp/Np +yiMOkUPjr2tLhV78Oba46xDLA6AiQ7yTPg+/ZYPIfbF2dPBTpfgGdly2M1xymRKc +3Pa+IUXkLw6oCA+lFzOFW0Swtekk9HRAgGyHgj6/Hvagva5Wer4HJIO1qRsFPew+ +XcM3uhhiXoiO8o+YGpJ/7kz0gED3p2b9OVsLPd8G/GfdR3miD+Au+kUx/27z/WdJ +ISfFILFnYeYZGffrpRcFtoGwuZUCugwnbLtpQpNKuGq8jDidm1v6Rb85JmkoH3Sg +lRaX1MK0aPhM4WfCf7aWCNe669FAWPNB3Ya2lue7ewPLI84ZUEqcoJwmWn2ci2SU +EXUCAwEAAaNjMGEwHQYDVR0OBBYEFG3hwzikpXqMasw678OHM8uLyjEoMB8GA1Ud +IwQYMBaAFG3hwzikpXqMasw678OHM8uLyjEoMA8GA1UdEwQIMAYBAf8CAQAwDgYD +VR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQA07URxJMI/Ta9y1wIg+k7o +1aHXsl6YOXmd2ymhKZhZHrZlutE2U19IQSoEV0SBddP9D05xD6Ovsrwo7caeYzNt ++2DJnlJ2IY61NqYUIDEoJyNPL/S7WleH+xO+bcSqWvbntTNYAD6WQVfHCAimVE6P +RnSZGqG089i84DRCyrh/6F1OxnBd6j14z+2ctQD+h6NlQXiCAUIwzVirYoE7oGpH +Xta7Ei+RDvBXLXLAQRdXpzSP/Ddf7MCJzmH3VYAy+0sVuHr09hpFMtC59hTrdLVD +/qma0eKrBr1DGH6QrZMZDqpNfv4wUPyVQBsRbbn2/1fL9IqK43CIj8RUllCOsmyU +-----END CERTIFICATE----- diff --git a/app/src/main/java/org/purplei2p/lightning/view/LightningWebClient.java b/app/src/main/java/org/purplei2p/lightning/view/LightningWebClient.java index 39811b5..3b384a5 100644 --- a/app/src/main/java/org/purplei2p/lightning/view/LightningWebClient.java +++ b/app/src/main/java/org/purplei2p/lightning/view/LightningWebClient.java @@ -9,6 +9,7 @@ import android.content.Intent; import android.graphics.Bitmap; import android.net.MailTo; import android.net.Uri; +import android.net.http.SslCertificate; import android.net.http.SslError; import android.os.Build; import android.os.Message; @@ -31,14 +32,29 @@ import android.webkit.WebViewClient; import android.widget.EditText; import android.widget.TextView; +import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.File; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.IOException; +import java.lang.reflect.Field; import java.net.URISyntaxException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.inject.Inject; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; import org.purplei2p.lightning.BuildConfig; import org.purplei2p.lightning.R; @@ -62,6 +78,8 @@ public class LightningWebClient extends WebViewClient { @NonNull private final UIController mUIController; @NonNull private final IntentUtils mIntentUtils; + private TrustManagerFactory tmf = null; + @Inject ProxyUtils mProxyUtils; @Inject AdBlock mAdBlock; @@ -74,6 +92,37 @@ public class LightningWebClient extends WebViewClient { mLightningView = lightningView; mAdBlock.updatePreference(); mIntentUtils = new IntentUtils(activity); + try { + initTrustStore(); + } catch(Exception e) {} + } + + private void initTrustStore() throws + CertificateException, FileNotFoundException, + IOException, KeyStoreException, NoSuchAlgorithmException { + + // Create a KeyStore containing our trusted CAs + String keyStoreType = KeyStore.getDefaultType(); + KeyStore trustedKeyStore = KeyStore.getInstance(keyStoreType); + trustedKeyStore.load(null, null); + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + + InputStream caInput = new BufferedInputStream(mActivity.getResources().getAssets().open("cert/purplei2p.crt")); + Certificate ca; + try { + ca = cf.generateCertificate(caInput); + Log.d(TAG, "ca-root DN=" + ((X509Certificate) ca).getSubjectDN()); + } + finally { + caInput.close(); + } + trustedKeyStore.setCertificateEntry("ca", ca); + + // Create a TrustManager that trusts the CAs in our KeyStore + String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); + tmf = TrustManagerFactory.getInstance(tmfAlgorithm); + tmf.init(trustedKeyStore); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) @@ -225,6 +274,40 @@ public class LightningWebClient extends WebViewClient { @Override public void onReceivedSslError(WebView view, @NonNull final SslErrorHandler handler, @NonNull SslError error) { + boolean passVerify = false; + + if(error.getPrimaryError() == SslError.SSL_UNTRUSTED){ + SslCertificate cert = error.getCertificate(); + String subjectDN = cert.getIssuedTo().getDName(); + Log.d(TAG, "SslError subjectDN: "+subjectDN); + try{ + Field f = cert.getClass().getDeclaredField("mX509Certificate"); + f.setAccessible(true); + X509Certificate x509 = (X509Certificate)f.get(cert); + + X509Certificate[] chain = {x509}; + for (TrustManager trustManager: tmf.getTrustManagers()) { + if (trustManager instanceof X509TrustManager) { + X509TrustManager x509TrustManager = (X509TrustManager)trustManager; + try{ + x509TrustManager.checkServerTrusted(chain, "generic"); + passVerify = true;break; + }catch(Exception e){ + Log.e(TAG, "SslError verify trustManager failed", e); + passVerify = false; + } + } + } + Log.d(TAG, "SslError passVerify: "+passVerify); + }catch(Exception e){ + Log.e(TAG, "SslError verify cert fail", e); + } + } + if(passVerify == true) { + handler.proceed(); + return; + } + List errorCodeMessageCodes = getAllSslErrorMessageCodes(error); StringBuilder stringBuilder = new StringBuilder();