summaryrefslogtreecommitdiff
path: root/app/src/main/java/de/blinkt/openvpn
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/de/blinkt/openvpn')
-rw-r--r--app/src/main/java/de/blinkt/openvpn/VpnProfile.java51
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java79
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java5
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/connection/Connection.java57
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java2
5 files changed, 149 insertions, 45 deletions
diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
index 9da1e452..9e71939b 100644
--- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
+++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
@@ -5,6 +5,8 @@
package de.blinkt.openvpn;
+import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4;
+import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_HOP;
import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE;
import static se.leap.bitmaskclient.base.utils.ConfigHelper.stringEqual;
@@ -41,6 +43,7 @@ import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
@@ -50,6 +53,7 @@ import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PSSParameterSpec;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Locale;
@@ -73,10 +77,12 @@ import de.blinkt.openvpn.core.VpnStatus;
import de.blinkt.openvpn.core.X509Utils;
import de.blinkt.openvpn.core.connection.Connection;
import de.blinkt.openvpn.core.connection.ConnectionAdapter;
+import de.blinkt.openvpn.core.connection.Obfs4Connection;
import se.leap.bitmaskclient.BuildConfig;
import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.base.models.ProviderObservable;
import se.leap.bitmaskclient.base.utils.PreferenceHelper;
+import se.leap.bitmaskclient.pluggableTransports.models.Obfs4Options;
public class VpnProfile implements Serializable, Cloneable {
// Note that this class cannot be moved to core where it belongs since
@@ -272,11 +278,20 @@ public class VpnProfile implements Serializable, Cloneable {
}
@Override
+ public int hashCode() {
+ int result =(mGatewayIp != null ? mGatewayIp.hashCode() : 0);
+ result = 31 * result + Arrays.hashCode(mConnections);
+ result = 31 * result + mTransportType;
+ return result;
+ }
+
+ @Override
public boolean equals(Object obj) {
if (obj instanceof VpnProfile) {
VpnProfile vp = (VpnProfile) obj;
return stringEqual(vp.mGatewayIp, mGatewayIp) &&
- vp.mTransportType == mTransportType;
+ vp.mTransportType == mTransportType &&
+ Arrays.equals(mConnections, vp.mConnections);
}
return false;
}
@@ -315,6 +330,22 @@ public class VpnProfile implements Serializable, Cloneable {
return Connection.TransportType.fromInt(mTransportType);
}
+ public @Nullable Obfs4Options getObfs4Options() {
+ Connection.TransportType transportType = getTransportType();
+ if (!(transportType == OBFS4 || transportType == OBFS4_HOP)) {
+ return null;
+ }
+ return ((Obfs4Connection) mConnections[0]).getObfs4Options();
+ }
+
+ public String getObfuscationTransportLayerProtocol() {
+ try {
+ return getObfs4Options().transport.getProtocols()[0];
+ } catch (NullPointerException | ArrayIndexOutOfBoundsException ignore) {
+ return null;
+ }
+ }
+
public String getName() {
if (TextUtils.isEmpty(mName))
return "No profile name";
@@ -444,8 +475,12 @@ public class VpnProfile implements Serializable, Cloneable {
// Client Cert + Key
cfg.append(insertFileData("cert", mClientCertFilename));
- mPrivateKey = ProviderObservable.getInstance().getCurrentProvider().getRSAPrivateKey();
- cfg.append("management-external-key nopadding pkcs1 pss digest\n");
+ mPrivateKey = ProviderObservable.getInstance().getCurrentProvider().getPrivateKey();
+ if (mPrivateKey.getAlgorithm().equalsIgnoreCase("RSA")) {
+ cfg.append("management-external-key nopadding pkcs1 pss digest\n");
+ } else {
+ cfg.append("management-external-key\n");
+ }
break;
case VpnProfile.TYPE_USERPASS_PKCS12:
@@ -1250,7 +1285,9 @@ public class VpnProfile implements Serializable, Cloneable {
return signed_bytes;
}
} catch
- (NoSuchAlgorithmException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException | SignatureException | InvalidAlgorithmParameterException
+ (NoSuchAlgorithmException | InvalidKeyException | IllegalBlockSizeException |
+ BadPaddingException | NoSuchPaddingException | SignatureException |
+ InvalidAlgorithmParameterException | NoSuchProviderException
e) {
VpnStatus.logError(R.string.error_rsa_sign, e.getClass().toString(), e.getLocalizedMessage());
return null;
@@ -1296,11 +1333,13 @@ public class VpnProfile implements Serializable, Cloneable {
return hashtype;
}
- private byte[] doDigestSign(PrivateKey privkey, byte[] data, OpenVPNManagement.SignaturePadding padding, String hashalg, String saltlen) throws SignatureException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException {
+ private byte[] doDigestSign(PrivateKey privkey, byte[] data, OpenVPNManagement.SignaturePadding padding, String hashalg, String saltlen) throws SignatureException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, NoSuchProviderException {
/* RSA */
Signature sig = null;
- if (privkey.getAlgorithm().equals("EC")) {
+ if (privkey.getAlgorithm().equals("Ed25519")) {
+ sig = Signature.getInstance("Ed25519", "BC");
+ } else if (privkey.getAlgorithm().equals("EC")) {
if (hashalg.equals(""))
hashalg = "NONE";
/* e.g. SHA512withECDSA */
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
index c8ac965f..a82a87d9 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
@@ -182,6 +182,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
synchronized (mProcessLock) {
mProcessThread = null;
}
+ stopObfsvpn();
VpnStatus.removeByteCountListener(this);
unregisterDeviceStateReceiver(mDeviceStateReceiver);
mDeviceStateReceiver = null;
@@ -230,15 +231,20 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
mDeviceStateReceiver.userPause(shouldBePaused);
}
+ private boolean stopObfsvpn() {
+ if (obfsVpnClient == null || !obfsVpnClient.isStarted()) {
+ return true;
+ }
+ boolean success = obfsVpnClient.stop();
+ obfsVpnClient = null;
+ return success;
+ }
@Override
public boolean stopVPN(boolean replaceConnection) {
+ stopObfsvpn();
if(isVpnRunning()) {
if (getManagement() != null && getManagement().stopVPN(replaceConnection)) {
if (!replaceConnection) {
- if (obfsVpnClient != null && obfsVpnClient.isStarted()) {
- obfsVpnClient.stop();
- obfsVpnClient = null;
- }
VpnStatus.updateStateString("NOPROCESS", "VPN STOPPED", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED);
}
return true;
@@ -369,24 +375,53 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
private void startOpenVPN() {
- //TODO: investigate how connections[n] with n>0 get called during vpn setup (on connection refused?)
- // Do we need to check if there's any obfs4 connection in mProfile.mConnections and start
- // the dispatcher here? Can we start the dispatcher at a later point of execution, e.g. when
- // connections[n], n>0 gets choosen?
-
Connection connection = mProfile.mConnections[0];
VpnStatus.setCurrentlyConnectingProfile(mProfile);
+ // stop old running obfsvpn client
+ if (!stopObfsvpn()) {
+ VpnStatus.logError("Failed to stop already running obfsvpn client");
+ endVpnService();
+ VpnStatus.updateStateString("NOPROCESS", "VPN STOPPED", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED);
+ return;
+ }
+
+ // Set a flag that we are starting a new VPN
+ mStarting = true;
+ // Stop the previous session by interrupting the thread.
+ stopOldOpenVPNProcess();
+ // An old running VPN should now be exited
+ mStarting = false;
+
+ // optionally start start obfsvpn and adapt openvpn config to the port obfsvpn is listening to
+ Connection.TransportType transportType = connection.getTransportType();
+ if (mProfile.usePluggableTransports() && transportType.isPluggableTransport()) {
+ try {
+ obfsVpnClient = new ObfsvpnClient(((Obfs4Connection) connection).getObfs4Options());
+ obfsVpnClient.start();
+ int port = obfsVpnClient.getPort();
+ connection.setServerPort(String.valueOf(port));
+ } catch (RuntimeException e) {
+ e.printStackTrace();
+ VpnStatus.logException(e);
+ endVpnService();
+ VpnStatus.updateStateString("NOPROCESS", "VPN STOPPED", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED);
+ return;
+ }
+ }
+
+ // write openvpn config
VpnStatus.logInfo(R.string.building_configration);
VpnStatus.updateStateString("VPN_GENERATE_CONFIG", "", R.string.building_configration, ConnectionStatus.LEVEL_START);
-
try {
mProfile.writeConfigFile(this);
} catch (IOException e) {
VpnStatus.logException("Error writing config file", e);
endVpnService();
+ VpnStatus.updateStateString("NOPROCESS", "VPN STOPPED", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED);
return;
}
+
String nativeLibraryDirectory = getApplicationInfo().nativeLibraryDir;
String tmpDir;
try {
@@ -399,25 +434,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
// Write OpenVPN binary
String[] argv = VPNLaunchHelper.buildOpenvpnArgv(this);
-
- // Set a flag that we are starting a new VPN
- mStarting = true;
- // Stop the previous session by interrupting the thread.
-
- stopOldOpenVPNProcess();
- // An old running VPN should now be exited
- mStarting = false;
- Connection.TransportType transportType = connection.getTransportType();
- if (mProfile.usePluggableTransports() && transportType.isPluggableTransport()) {
- if (obfsVpnClient != null && obfsVpnClient.isStarted()) {
- obfsVpnClient.stop();
- }
- obfsVpnClient = new ObfsvpnClient(((Obfs4Connection) connection).getObfs4Options());
- obfsVpnClient.start();
- Log.d(TAG, "obfsvpn client started");
- }
-
-
// Start a new session by creating a new thread.
boolean useOpenVPN3 = VpnProfile.doUseOpenVPN3(this);
@@ -471,11 +487,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
if (mOpenVPNThread != null)
((OpenVPNThread) mOpenVPNThread).setReplaceConnection();
if (mManagement.stopVPN(true)) {
- if (obfsVpnClient != null && obfsVpnClient.isStarted()) {
- Log.d(TAG, "-> stop obfsvpnClient");
- obfsVpnClient.stop();
- obfsVpnClient = null;
- }
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
index 88b933eb..a4b5e3be 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
@@ -272,12 +272,13 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
}
private void processCommand(String command) {
- //Log.i(TAG, "Line from managment" + command);
+ Log.i(TAG, "Line from managment " + command);
if (command.startsWith(">") && command.contains(":")) {
String[] parts = command.split(":", 2);
String cmd = parts[0].substring(1);
String argument = parts[1];
+ Log.d(">>>>", "CMD: "+ cmd + "argument: " + argument);
switch (cmd) {
@@ -735,7 +736,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
String[] arguments = argument.split(",");
// NC9t8IkYrjAQcCzc85zN0H5TvwfAUDwYkR4j2ga6fGw=,RSA_PKCS1_PSS_PADDING,hashalg=SHA256,saltlen=digest
-
+ // ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRMUyAxLjMsIGNsaWVudCBIoXJ0aWZpY2F0ZVZlcmlmeQCvvTk69HvSHUhM27ghCCSgzHds1Bdsm4MyVGxlgDIJbnDj+G5Y1YxXajqy6E/G1GA=,ED25519,data=message
SignaturePadding padding = SignaturePadding.NO_PADDING;
String saltlen="";
diff --git a/app/src/main/java/de/blinkt/openvpn/core/connection/Connection.java b/app/src/main/java/de/blinkt/openvpn/core/connection/Connection.java
index 0b28cbca..6cd86105 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/connection/Connection.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/connection/Connection.java
@@ -9,10 +9,13 @@ import static de.blinkt.openvpn.core.connection.Connection.TransportType.*;
import android.text.TextUtils;
+import androidx.annotation.NonNull;
+
import com.google.gson.annotations.JsonAdapter;
import java.io.Serializable;
import java.util.Locale;
+import java.util.Objects;
@JsonAdapter(ConnectionAdapter.class)
public abstract class Connection implements Serializable, Cloneable {
@@ -42,7 +45,8 @@ public abstract class Connection implements Serializable, Cloneable {
public enum TransportProtocol {
UDP("udp"),
TCP("tcp"),
- KCP("kcp");
+ KCP("kcp"),
+ QUIC("quic");
final String protocol;
@@ -301,5 +305,54 @@ public abstract class Connection implements Serializable, Cloneable {
this.mProxyAuthPassword = proxyAuthPassword;
}
- public abstract TransportType getTransportType();
+ public abstract @NonNull TransportType getTransportType();
+
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Connection that)) return false;
+
+ if (mUseUdp != that.mUseUdp) return false;
+ if (mUseCustomConfig != that.mUseCustomConfig) return false;
+ if (mEnabled != that.mEnabled) return false;
+ if (mConnectTimeout != that.mConnectTimeout) return false;
+ if (mUseProxyAuth != that.mUseProxyAuth) return false;
+ if (!Objects.equals(mServerName, that.mServerName))
+ return false;
+ if (!Objects.equals(mServerPort, that.mServerPort))
+ return false;
+ if (!Objects.equals(mCustomConfiguration, that.mCustomConfiguration))
+ return false;
+ if (mProxyType != that.mProxyType) return false;
+ if (!Objects.equals(mProxyName, that.mProxyName))
+ return false;
+ if (!Objects.equals(mProxyPort, that.mProxyPort))
+ return false;
+ if (!Objects.equals(mProxyAuthUser, that.mProxyAuthUser))
+ return false;
+ if (getTransportType() != that.getTransportType()) {
+ return false;
+ }
+ return Objects.equals(mProxyAuthPassword, that.mProxyAuthPassword);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mServerName != null ? mServerName.hashCode() : 0;
+ result = 31 * result + (mServerPort != null ? mServerPort.hashCode() : 0);
+ result = 31 * result + (mUseUdp ? 1 : 0);
+ result = 31 * result + (mCustomConfiguration != null ? mCustomConfiguration.hashCode() : 0);
+ result = 31 * result + (mUseCustomConfig ? 1 : 0);
+ result = 31 * result + (mEnabled ? 1 : 0);
+ result = 31 * result + mConnectTimeout;
+ result = 31 * result + (mProxyType != null ? mProxyType.hashCode() : 0);
+ result = 31 * result + (mProxyName != null ? mProxyName.hashCode() : 0);
+ result = 31 * result + (mProxyPort != null ? mProxyPort.hashCode() : 0);
+ result = 31 * result + (mUseProxyAuth ? 1 : 0);
+ result = 31 * result + (mProxyAuthUser != null ? mProxyAuthUser.hashCode() : 0);
+ result = 31 * result + (mProxyAuthPassword != null ? mProxyAuthPassword.hashCode() : 0);
+ result = 31 * result + getTransportType().toInt();
+ return result;
+ }
}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java b/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java
index 0fe6bff2..e2c596ac 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java
@@ -15,7 +15,7 @@ public class Obfs4Connection extends Connection {
public Obfs4Connection(Obfs4Options options) {
setServerName(ObfsvpnClient.IP);
- setServerPort(String.valueOf(ObfsvpnClient.PORT));
+ setServerPort(String.valueOf(ObfsvpnClient.DEFAULT_PORT));
setUseUdp(true);
setProxyType(ProxyType.NONE);
setProxyName("");