diff options
Diffstat (limited to 'app/src/main/java/de/blinkt/openvpn')
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(""); |