Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

Commit

Permalink
Skip certificate verification for tor connections (#242)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelWuensch authored Aug 21, 2020
1 parent ae5bf47 commit 7772f2d
Show file tree
Hide file tree
Showing 21 changed files with 185 additions and 136 deletions.
2 changes: 1 addition & 1 deletion app/src/main/java/zapsolutions/zap/HomeActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
import zapsolutions.zap.baseClasses.BaseAppCompatActivity;
import zapsolutions.zap.channelManagement.ManageChannelsActivity;
import zapsolutions.zap.connection.RemoteConfiguration;
import zapsolutions.zap.connection.establishConnectionToLnd.LndConnection;
import zapsolutions.zap.connection.lndConnection.LndConnection;
import zapsolutions.zap.connection.internetConnectionStatus.NetworkChangeReceiver;
import zapsolutions.zap.connection.manageWalletConfigs.WalletConfigsManager;
import zapsolutions.zap.customView.CustomViewPager;
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package zapsolutions.zap.connection.lndConnection;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;

/**
* This HostnameVerifier trust all host names. No verification will take place.
* In our context we only use it for tor connections and in debug builds to simplify the regtest setup.
*/
public class BlindHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package zapsolutions.zap.connection.lndConnection;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

/**
* This TrustManager trust ALL certificates. No validation takes place.
* In our context we use it only for tor connections.
*/
public class BlindTrustManager implements X509TrustManager {

public X509Certificate[] getAcceptedIssuers() {
return null;
}

public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {

}

public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {

}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package zapsolutions.zap.connection.establishConnectionToLnd;
package zapsolutions.zap.connection.lndConnection;


import com.google.common.io.BaseEncoding;

import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSocketFactory;

import io.grpc.ManagedChannel;
import io.grpc.okhttp.OkHttpChannelBuilder;
Expand Down Expand Up @@ -42,7 +39,6 @@ public class LndConnection {

private static LndConnection mLndConnectionInstance;

private SSLSocketFactory mSSLFactory;
private MacaroonCallCredential mMacaroon;
private ManagedChannel mSecureChannel;
private LndAutopilotService mLndAutopilotService;
Expand Down Expand Up @@ -111,50 +107,26 @@ private void readSavedConnectionInfo() {

// Generate Macaroon
mMacaroon = new MacaroonCallCredential(mConnectionConfig.getMacaroon());

mSSLFactory = null;

// Generate certificate if one was supplied
if (mConnectionConfig.getCert() != null) {
// We have a certificate, try to load it.

String certificateBase64UrlString = mConnectionConfig.getCert();
byte[] certificateBytes = BaseEncoding.base64Url().decode(certificateBase64UrlString);

try {
mSSLFactory = CustomSSLSocketFactory.create(certificateBytes);
} catch (RuntimeException e) {
ZapLog.e(LOG_TAG, "Error creating certificate");
}

}
}

private void generateChannelAndStubs() {
String host = mConnectionConfig.getHost();
int port = mConnectionConfig.getPort();

HostnameVerifier hostnameVerifier = null; // null = default hostnameVerifier
if (BuildConfig.BUILD_TYPE.equals("debug")) {
HostnameVerifier hostnameVerifier = null;
if (BuildConfig.BUILD_TYPE.equals("debug") || mConnectionConfig.isTor()) {
// Disable hostname verification on debug build variant. This is is used to prevent connection errors to REGTEST nodes.
hostnameVerifier = new HostnameVerifierAllowAll();
// On Tor we do not need it, as tor already makes sure we are connected with the correct host.
hostnameVerifier = new BlindHostnameVerifier();
}

// Channels are expensive to create. We want to create it once and then reuse it on all our requests.
if (mSSLFactory == null) {
// BTCPay
mSecureChannel = OkHttpChannelBuilder
.forAddress(host, port)
.hostnameVerifier(hostnameVerifier)
.build();

} else {
mSecureChannel = OkHttpChannelBuilder
.forAddress(host, port)
.hostnameVerifier(hostnameVerifier)
.sslSocketFactory(mSSLFactory)
.build();
}
mSecureChannel = OkHttpChannelBuilder
.forAddress(host, port)
.hostnameVerifier(hostnameVerifier) // null = default hostnameVerifier
.sslSocketFactory(LndSSLSocketFactory.create(mConnectionConfig)) // null = default SSLSocketFactory
.build();


mLndAutopilotService = new RemoteLndAutopilotService(mSecureChannel, mMacaroon);
mLndChainNotifierService = new RemoteLndChainNotifierService(mSecureChannel, mMacaroon);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package zapsolutions.zap.connection.lndConnection;

import com.google.common.io.BaseEncoding;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

import zapsolutions.zap.connection.manageWalletConfigs.WalletConfig;
import zapsolutions.zap.util.ZapLog;

/**
* Creates an SSLSocketFactory instance for use with a self signed Certificate,
* which would otherwise be considered "not trustworthy".
* This can be fed into HttpsURLConnection, as well as networking libraries such as OkHttp's OkHttpClient.
*/
public class LndSSLSocketFactory {

private static final String LOG_TAG = LndSSLSocketFactory.class.getName();

private LndSSLSocketFactory() {
throw new AssertionError();
}

public static SSLSocketFactory create(WalletConfig walletConfig) {
SSLContext sslCtx = null;

try {
sslCtx = SSLContext.getInstance("TLS");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}

if (walletConfig.isTor()) {
// Always trust the certificate on Tor connection
try {
sslCtx.init(null, new TrustManager[]{new BlindTrustManager()}, null);
} catch (KeyManagementException e) {
e.printStackTrace();
return null;
}
return sslCtx.getSocketFactory();

} else {
// On clearnet we want to validate the certificate.
if (walletConfig.getCert() != null && !walletConfig.getCert().isEmpty()) {
//try to create a trustmanager that trust the certificate that was transmitted with the lndconnect string.
try {
InputStream caInput = null;
String certificateBase64UrlString = walletConfig.getCert();
byte[] certificateBytes = BaseEncoding.base64Url().decode(certificateBase64UrlString);

// Generate the CA Certificate from the supplied byte array
caInput = new ByteArrayInputStream(certificateBytes);
Certificate ca = CertificateFactory.getInstance("X.509").generateCertificate(caInput);

// Load the key store using the CA
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);

// Initialize the TrustManager with this CA
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);

// Create an SSL context that uses the created trust manager
sslCtx.init(null, tmf.getTrustManagers(), new SecureRandom());
return sslCtx.getSocketFactory();

} catch (Exception e) {
ZapLog.e(LOG_TAG, "Error while initializing self signed certificate.");
e.printStackTrace();
}
}
}

// If the above failed, use the default TrustManager which is used when set to null
// This will be the case for btc pay for example as no self signed certificates are used
try {
sslCtx.init(null, null, new SecureRandom());
} catch (KeyManagementException e) {
e.printStackTrace();
return null;
}
return sslCtx.getSocketFactory();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package zapsolutions.zap.connection.establishConnectionToLnd;
package zapsolutions.zap.connection.lndConnection;

import java.util.concurrent.Executor;

Expand Down Expand Up @@ -30,7 +30,6 @@ public void applyRequestMetadata(
final MetadataApplier metadataApplier
) {
String authority = requestInfo.getAuthority();
// System.out.println(authority);
executor.execute(new Runnable() {
public void run() {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ public WalletConfig (String id) {
this.id = id;
}

public boolean isTor() {
if (getHost() == null) {
return false;
}
return getHost().toLowerCase().endsWith(".onion");
}

@Override
public int compareTo(WalletConfig walletConfig) {
WalletConfig other = walletConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

import com.google.common.io.BaseEncoding;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;

import zapsolutions.zap.connection.establishConnectionToLnd.CustomSSLSocketFactory;
import zapsolutions.zap.connection.parseConnectionData.BaseConnectionParser;
import zapsolutions.zap.util.ZapLog;

Expand Down Expand Up @@ -81,10 +85,13 @@ public LndConnectStringParser parse() {
try {
byte[] certificateBytes = BaseEncoding.base64Url().decode(cert);
try {
CustomSSLSocketFactory.create(certificateBytes);
} catch (RuntimeException e) {

ZapLog.e(LOG_TAG, "certificate creation failed");
// Generate the CA Certificate from the supplied byte array
InputStream caInput = null;
caInput = new ByteArrayInputStream(certificateBytes);
Certificate ca = CertificateFactory.getInstance("X.509").generateCertificate(caInput);
} catch (CertificateException e) {
e.printStackTrace();
ZapLog.e(LOG_TAG, "certificate validation failed");
mError = ERROR_INVALID_CERTIFICATE;
return this;
}
Expand Down Expand Up @@ -113,7 +120,7 @@ public LndConnectStringParser parse() {
}
}

// everything is ok, initiate connection
// everything is ok
LndConnectConfig lndConnectConfig = new LndConnectConfig();
lndConnectConfig.setHost(connectURI.getHost());
lndConnectConfig.setPort(connectURI.getPort());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
import zapsolutions.zap.GeneratedRequestActivity;
import zapsolutions.zap.R;
import zapsolutions.zap.channelManagement.ManageChannelsActivity;
import zapsolutions.zap.connection.establishConnectionToLnd.LndConnection;
import zapsolutions.zap.connection.lndConnection.LndConnection;
import zapsolutions.zap.connection.manageWalletConfigs.WalletConfigsManager;
import zapsolutions.zap.customView.NumpadView;
import zapsolutions.zap.util.HelpDialogUtil;
Expand Down
Loading

0 comments on commit 7772f2d

Please sign in to comment.