From c89414179f77982751064a5709122913c3ffd6c4 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sat, 9 Feb 2013 17:03:27 +0100 Subject: Merge non OpenVPN3 specific into main --- .hgignore | 5 +- jni/jbcrypto.cpp | 4 +- res/values/strings.xml | 1 + src/de/blinkt/openvpn/CIDRIP.java | 6 + src/de/blinkt/openvpn/LogWindow.java | 38 +++++- src/de/blinkt/openvpn/NetworkSateReceiver.java | 16 ++- src/de/blinkt/openvpn/OpenVPN.java | 9 +- src/de/blinkt/openvpn/OpenVPNMangement.java | 13 ++ src/de/blinkt/openvpn/OpenVpnManagementThread.java | 120 +++-------------- src/de/blinkt/openvpn/OpenVpnService.java | 123 ++++++++++++----- src/de/blinkt/openvpn/ShowConfigFragment.java | 32 ++++- src/de/blinkt/openvpn/VpnProfile.java | 148 +++++++++++++++++---- 12 files changed, 338 insertions(+), 177 deletions(-) create mode 100644 src/de/blinkt/openvpn/OpenVPNMangement.java diff --git a/.hgignore b/.hgignore index 7a6193b8..e6d2de68 100644 --- a/.hgignore +++ b/.hgignore @@ -24,7 +24,7 @@ openvpn/build/msvc/Makefile.in openvpn/src/openvpn/.deps openvpn/src/compat/.deps *.o - +ovpn3 *.patch openvpn/distro/Makefile.in openvpn/distro/rpm/Makefile.in @@ -62,4 +62,5 @@ ics-openvpn.zip zh-CN.zip zh-TW.zip google-breakpad/ -id.zip \ No newline at end of file +id.zip +ovpn3/boost \ No newline at end of file diff --git a/jni/jbcrypto.cpp b/jni/jbcrypto.cpp index 8bc6fb8d..77382fb9 100644 --- a/jni/jbcrypto.cpp +++ b/jni/jbcrypto.cpp @@ -17,7 +17,7 @@ extern "C" { -jbyteArray Java_de_blinkt_openvpn_OpenVpnManagementThread_rsasign(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef); +jbyteArray Java_de_blinkt_openvpn_VpnProfile_rsasign(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef); } int jniThrowException(JNIEnv* env, const char* className, const char* msg) { @@ -41,7 +41,7 @@ int jniThrowException(JNIEnv* env, const char* className, const char* msg) { } -jbyteArray Java_de_blinkt_openvpn_OpenVpnManagementThread_rsasign(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef) { +jbyteArray Java_de_blinkt_openvpn_VpnProfile_rsasign(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef) { // EVP_MD_CTX* ctx = reinterpret_cast(ctxRef); EVP_PKEY* pkey = reinterpret_cast(pkeyRef); diff --git a/res/values/strings.xml b/res/values/strings.xml index da98236a..8dc15806 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -247,6 +247,7 @@ Assigning IP addresses Adding routes Connected + Disconnect Reconnecting Exiting Not running diff --git a/src/de/blinkt/openvpn/CIDRIP.java b/src/de/blinkt/openvpn/CIDRIP.java index d3939dfc..41b56d4b 100644 --- a/src/de/blinkt/openvpn/CIDRIP.java +++ b/src/de/blinkt/openvpn/CIDRIP.java @@ -5,6 +5,8 @@ import java.util.Locale; class CIDRIP{ String mIp; int len; + + public CIDRIP(String ip, String mask){ mIp=ip; long netmask=getInt(mask); @@ -26,6 +28,10 @@ class CIDRIP{ } } + public CIDRIP(String address, int prefix_length) { + len = prefix_length; + mIp = address; + } @Override public String toString() { return String.format(Locale.ENGLISH,"%s/%d",mIp,len); diff --git a/src/de/blinkt/openvpn/LogWindow.java b/src/de/blinkt/openvpn/LogWindow.java index 8d6df5e5..4d2047f8 100644 --- a/src/de/blinkt/openvpn/LogWindow.java +++ b/src/de/blinkt/openvpn/LogWindow.java @@ -7,14 +7,17 @@ import android.app.AlertDialog.Builder; import android.app.ListActivity; import android.content.ClipData; import android.content.ClipboardManager; +import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; +import android.content.ServiceConnection; import android.database.DataSetObserver; import android.os.Bundle; import android.os.Handler; import android.os.Handler.Callback; +import android.os.IBinder; import android.os.Message; import android.view.Menu; import android.view.MenuInflater; @@ -30,10 +33,31 @@ import android.widget.Toast; import de.blinkt.openvpn.OpenVPN.LogItem; import de.blinkt.openvpn.OpenVPN.LogListener; import de.blinkt.openvpn.OpenVPN.StateListener; +import de.blinkt.openvpn.OpenVpnService.LocalBinder; public class LogWindow extends ListActivity implements StateListener { private static final int START_VPN_CONFIG = 0; private String[] mBconfig=null; + protected OpenVpnService mService; + private ServiceConnection mConnection = new ServiceConnection() { + + + + @Override + public void onServiceConnected(ComponentName className, + IBinder service) { + // We've bound to LocalService, cast the IBinder and get LocalService instance + LocalBinder binder = (LocalBinder) service; + mService = binder.getService(); + } + + @Override + public void onServiceDisconnected(ComponentName arg0) { + mService =null; + } + + }; + class LogWindowListAdapter implements ListAdapter, LogListener, Callback { @@ -198,6 +222,7 @@ public class LogWindow extends ListActivity implements StateListener { private LogWindowListAdapter ladapter; private TextView mSpeedView; + @Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId()==R.id.clearlog) { @@ -213,7 +238,8 @@ public class LogWindow extends ListActivity implements StateListener { @Override public void onClick(DialogInterface dialog, int which) { ProfileManager.setConntectedVpnProfileDisconnected(getApplicationContext()); - OpenVpnManagementThread.stopOpenVPN(); + if(mService.getManagement()!=null) + mService.getManagement().stopVPN(); } }); @@ -335,6 +361,11 @@ public class LogWindow extends ListActivity implements StateListener { mSpeedView = (TextView) findViewById(R.id.speed); getActionBar().setDisplayHomeAsUpEnabled(true); + Intent intent = new Intent(getBaseContext(), OpenVpnService.class); + intent.setAction(OpenVpnService.START_SERVICE); + + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + } @Override @@ -346,6 +377,8 @@ public class LogWindow extends ListActivity implements StateListener { String prefix=getString(resid) + ":"; if (status.equals("BYTECOUNT") || status.equals("NOPROCESS") ) prefix=""; + if (resid==R.string.unknown_state) + prefix+=status; mSpeedView.setText(prefix + logmessage); } }); @@ -354,8 +387,9 @@ public class LogWindow extends ListActivity implements StateListener { @Override protected void onDestroy() { - super.onDestroy(); + unbindService(mConnection); OpenVPN.removeLogListener(ladapter); + super.onDestroy(); } } diff --git a/src/de/blinkt/openvpn/NetworkSateReceiver.java b/src/de/blinkt/openvpn/NetworkSateReceiver.java index e20c8e52..487639a9 100644 --- a/src/de/blinkt/openvpn/NetworkSateReceiver.java +++ b/src/de/blinkt/openvpn/NetworkSateReceiver.java @@ -11,13 +11,13 @@ import android.preference.PreferenceManager; public class NetworkSateReceiver extends BroadcastReceiver { private int lastNetwork=-1; - private OpenVpnManagementThread mManangement; + private OpenVPNMangement mManangement; private String lastStateMsg=null; - public NetworkSateReceiver(OpenVpnManagementThread managementThread) { + public NetworkSateReceiver(OpenVPNMangement magnagement) { super(); - mManangement = managementThread; + mManangement = magnagement; } @Override @@ -57,15 +57,19 @@ public class NetworkSateReceiver extends BroadcastReceiver { if(networkInfo!=null && networkInfo.getState() == State.CONNECTED) { int newnet = networkInfo.getType(); - if(sendusr1 && lastNetwork!=newnet) - mManangement.reconnect(); + if(sendusr1 && lastNetwork!=newnet) { + if (lastNetwork==-1) + mManangement.resume(); + else + mManangement.reconnect(); + } lastNetwork = newnet; } else if (networkInfo==null) { // Not connected, stop openvpn, set last connected network to no network lastNetwork=-1; if(sendusr1) - mManangement.signalusr1(); + mManangement.pause(); } if(!netstatestring.equals(lastStateMsg)) diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java index c1616f2d..2ca2d259 100644 --- a/src/de/blinkt/openvpn/OpenVPN.java +++ b/src/de/blinkt/openvpn/OpenVPN.java @@ -173,6 +173,8 @@ public class OpenVPN { return R.string.state_add_routes; else if (state.equals("CONNECTED")) return R.string.state_connected; + else if (state.equals("DISCONNECTED")) + return R.string.state_disconnected; else if (state.equals("RECONNECTING")) return R.string.state_reconnecting; else if (state.equals("EXITING")) @@ -257,7 +259,12 @@ public class OpenVPN { newlogItem(new LogItem(LogItem.ERROR, ressourceId,args)); } - public static void updateByteCount(long in, long out, long diffin, long diffout) { + public static void updateByteCount(long in, long out) { + long lastIn = mlastByteCount[0]; + long lastOut = mlastByteCount[1]; + long diffin = in - lastIn; + long diffout = out - lastOut; + mlastByteCount = new long[] {in,out,diffin,diffout}; for(ByteCountListener bcl:byteCountListener){ bcl.updateByteCount(in, out, diffin,diffout); diff --git a/src/de/blinkt/openvpn/OpenVPNMangement.java b/src/de/blinkt/openvpn/OpenVPNMangement.java new file mode 100644 index 00000000..0c6d7163 --- /dev/null +++ b/src/de/blinkt/openvpn/OpenVPNMangement.java @@ -0,0 +1,13 @@ +package de.blinkt.openvpn; + +public interface OpenVPNMangement { + + void reconnect(); + + void pause(); + + void resume(); + + boolean stopVPN(); + +} diff --git a/src/de/blinkt/openvpn/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/OpenVpnManagementThread.java index 381fee82..e4528132 100644 --- a/src/de/blinkt/openvpn/OpenVpnManagementThread.java +++ b/src/de/blinkt/openvpn/OpenVpnManagementThread.java @@ -7,28 +7,18 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; import java.util.LinkedList; import java.util.Locale; import java.util.Vector; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; - import android.content.SharedPreferences; import android.net.LocalServerSocket; import android.net.LocalSocket; -import android.os.Build; import android.os.ParcelFileDescriptor; import android.preference.PreferenceManager; -import android.util.Base64; import android.util.Log; -public class OpenVpnManagementThread implements Runnable { +public class OpenVpnManagementThread implements Runnable, OpenVPNMangement { private static final String TAG = "openvpn"; private LocalSocket mSocket; @@ -36,8 +26,6 @@ public class OpenVpnManagementThread implements Runnable { private OpenVpnService mOpenVPNService; private LinkedList mFDList=new LinkedList(); private int mBytecountinterval=2; - private long mLastIn=0; - private long mLastOut=0; private LocalServerSocket mServerSocket; private boolean mReleaseHold=true; private boolean mWaitingForRelease=false; @@ -46,7 +34,6 @@ public class OpenVpnManagementThread implements Runnable { private static Vector active=new Vector(); static private native void jniclose(int fdint); - static private native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException; public OpenVpnManagementThread(VpnProfile profile, LocalServerSocket mgmtsocket, OpenVpnService openVpnService) { mProfile = profile; @@ -285,13 +272,7 @@ public class OpenVpnManagementThread implements Runnable { long in = Long.parseLong(argument.substring(0, comma)); long out = Long.parseLong(argument.substring(comma+1)); - long diffin = in - mLastIn; - long diffout = out - mLastOut; - - mLastIn=in; - mLastOut=out; - - OpenVPN.updateByteCount(in,out,diffin, diffout); + OpenVPN.updateByteCount(in,out); } @@ -449,7 +430,7 @@ public class OpenVpnManagementThread implements Runnable { } - public static boolean stopOpenVPN() { + private static boolean stopOpenVPN() { boolean sendCMD=false; for (OpenVpnManagementThread mt: active){ mt.managmentCommand("signal SIGINT\n"); @@ -477,89 +458,24 @@ public class OpenVpnManagementThread implements Runnable { private void processSignCommand(String b64data) { - PrivateKey privkey = mProfile.getKeystoreKey(); - Exception err =null; - - byte[] data = Base64.decode(b64data, Base64.DEFAULT); - - // The Jelly Bean *evil* Hack - // 4.2 implements the RSA/ECB/PKCS1PADDING in the OpenSSLprovider - if(Build.VERSION.SDK_INT==Build.VERSION_CODES.JELLY_BEAN){ - processSignJellyBeans(privkey,data); - return; - } - - - try{ - - - Cipher rsasinger = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); - - rsasinger.init(Cipher.ENCRYPT_MODE, privkey); - - byte[] signed_bytes = rsasinger.doFinal(data); - String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP); - managmentCommand("rsa-sig\n"); - managmentCommand(signed_string); - managmentCommand("\nEND\n"); - } catch (NoSuchAlgorithmException e){ - err =e; - } catch (InvalidKeyException e) { - err =e; - } catch (NoSuchPaddingException e) { - err =e; - } catch (IllegalBlockSizeException e) { - err =e; - } catch (BadPaddingException e) { - err =e; - } - if(err !=null) { - OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage()); - } - + String signed_string = mProfile.getSignedData(b64data); + managmentCommand("rsa-sig\n"); + managmentCommand(signed_string); + managmentCommand("\nEND\n"); } + @Override + public void pause() { + signalusr1(); + } - private void processSignJellyBeans(PrivateKey privkey, byte[] data) { - Exception err =null; - try { - Method[] allm = privkey.getClass().getSuperclass().getDeclaredMethods(); - System.out.println(allm); - Method getKey = privkey.getClass().getSuperclass().getDeclaredMethod("getOpenSSLKey"); - getKey.setAccessible(true); - - // Real object type is OpenSSLKey - Object opensslkey = getKey.invoke(privkey); - - getKey.setAccessible(false); - - Method getPkeyContext = opensslkey.getClass().getDeclaredMethod("getPkeyContext"); - - // integer pointer to EVP_pkey - getPkeyContext.setAccessible(true); - int pkey = (Integer) getPkeyContext.invoke(opensslkey); - getPkeyContext.setAccessible(false); - - byte[] signed_bytes = rsasign(data, pkey); - String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP); - managmentCommand("rsa-sig\n"); - managmentCommand(signed_string); - managmentCommand("\nEND\n"); - - } catch (NoSuchMethodException e) { - err=e; - } catch (IllegalArgumentException e) { - err=e; - } catch (IllegalAccessException e) { - err=e; - } catch (InvocationTargetException e) { - err=e; - } catch (InvalidKeyException e) { - err=e; - } - if(err !=null) { - OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage()); - } + @Override + public void resume() { + releaseHold(); + } + @Override + public boolean stopVPN() { + return stopOpenVPN(); } } diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index 6103ff89..ce9f75a1 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -27,6 +27,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.LocalServerSocket; import android.net.LocalSocket; @@ -38,6 +39,7 @@ import android.os.Handler.Callback; import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; +import android.preference.PreferenceManager; import de.blinkt.openvpn.OpenVPN.ByteCountListener; import de.blinkt.openvpn.OpenVPN.StateListener; @@ -60,9 +62,6 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac private CIDRIP mLocalIP=null; - private OpenVpnManagementThread mManagementThread; - - private Thread mSocketManagerThread; private int mMtu; private String mLocalIPv6=null; private NetworkSateReceiver mNetworkStateReceiver; @@ -86,6 +85,9 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac private static boolean mNotificationalwaysVisible=false; private final IBinder mBinder = new LocalBinder(); + private boolean mOvpn3; + private Thread mSocketManagerThread; + private OpenVPNMangement mManagement; public class LocalBinder extends Binder { public OpenVpnService getService() { @@ -105,7 +107,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac @Override public void onRevoke() { - OpenVpnManagementThread.stopOpenVPN(); + mManagement.stopVPN(); endVpnService(); } @@ -119,10 +121,13 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac OpenVPN.logBuilderConfig(null); OpenVPN.removeStateListener(this); OpenVPN.removeByteCountListener(this); + unregisterNetworkStateReceiver(); ProfileManager.setConntectedVpnProfileDisconnected(this); if(!mStarting) { - stopSelf(); - stopForeground(true); + stopForeground(!mNotificationalwaysVisible); + + if( !mNotificationalwaysVisible) + stopSelf(); } } @@ -171,7 +176,9 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // PRIORITY_MIN == -2 setpriority.invoke(nbuilder, -2 ); - nbuilder.setUsesChronometer(true); + Method setUsesChronometer = nbuilder.getClass().getMethod("setUsesChronometer", boolean.class); + setUsesChronometer.invoke(nbuilder,true); + /* PendingIntent cancelconnet=null; nbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel, @@ -229,14 +236,20 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac } - void registerNetworkStateReceiver() { + void registerNetworkStateReceiver(OpenVPNMangement magnagement) { // Registers BroadcastReceiver to track network connection changes. IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); - mNetworkStateReceiver = new NetworkSateReceiver(mManagementThread); + mNetworkStateReceiver = new NetworkSateReceiver(magnagement); this.registerReceiver(mNetworkStateReceiver, filter); } - + void unregisterNetworkStateReceiver() { + if(mNetworkStateReceiver!=null) + this.unregisterReceiver(mNetworkStateReceiver); + mNetworkStateReceiver=null; + } + + @Override public int onStartCommand(Intent intent, int flags, int startId) { @@ -263,18 +276,16 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac showNotification("Starting VPN " + mProfile.mName,"Starting VPN " + mProfile.mName, false,0,LEVEL_NOTCONNECTED); - - // Set a flag that we are starting a new VPN mStarting=true; // Stop the previous session by interrupting the thread. - if(OpenVpnManagementThread.stopOpenVPN()){ - // an old was asked to exit, wait 2s + if(mManagement!=null && mManagement.stopVPN()) + // an old was asked to exit, wait 1s try { Thread.sleep(1000); } catch (InterruptedException e) { } - } + if (mProcessThread!=null) { mProcessThread.interrupt(); @@ -288,33 +299,72 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // Open the Management Interface - LocalServerSocket mgmtsocket = openManagmentInterface(8); - - if(mgmtsocket!=null) { - // start a Thread that handles incoming messages of the managment socket - mManagementThread=new OpenVpnManagementThread(mProfile,mgmtsocket,this); - mSocketManagerThread = new Thread(mManagementThread,"OpenVPNMgmtThread"); - mSocketManagerThread.start(); - OpenVPN.logInfo("started Socket Thread"); - registerNetworkStateReceiver(); + if(!mOvpn3) { + LocalServerSocket mgmtsocket = openManagmentInterface(8); + + if(mgmtsocket!=null) { + // start a Thread that handles incoming messages of the managment socket + OpenVpnManagementThread ovpnmgmthread = new OpenVpnManagementThread(mProfile,mgmtsocket,this); + mSocketManagerThread = new Thread(ovpnmgmthread,"OpenVPNMgmtThread"); + mSocketManagerThread.start(); + mManagement= ovpnmgmthread; + OpenVPN.logInfo("started Socket Thread"); + } } - // Start a new session by creating a new thread. - OpenVPNThread processThread = new OpenVPNThread(this, argv,nativelibdir); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + + mOvpn3 = prefs.getBoolean("ovpn3", false); + + Runnable processThread; + if(mOvpn3) { + + OpenVPNMangement mOpenVPN3 = instantiateOpenVPN3Core(); + processThread = (Runnable) mOpenVPN3; + mManagement = mOpenVPN3; + + + } else { + processThread = new OpenVPNThread(this, argv,nativelibdir); + } mProcessThread = new Thread(processThread, "OpenVPNProcessThread"); mProcessThread.start(); + registerNetworkStateReceiver(mManagement); + + ProfileManager.setConnectedVpnProfile(this, mProfile); return START_NOT_STICKY; } + private OpenVPNMangement instantiateOpenVPN3Core() { + //new OpenVPNThreadv3(this,mProfile); + try { + Class cl = Class.forName("Lde/blinkt/openvpn/OpenVPNThreadv3;"); + return (OpenVPNMangement) cl.getConstructor(OpenVpnService.class,VpnProfile.class).newInstance(this,mProfile); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + return null; + } + @Override public void onDestroy() { if (mProcessThread != null) { - mManagementThread.managmentCommand("signal SIGINT\n"); + mManagement.stopVPN(); mProcessThread.interrupt(); } @@ -452,6 +502,10 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac } + public void addRoute(CIDRIP route) + { + mRoutes.add(route ); + } public void addRoute(String dest, String mask) { CIDRIP route = new CIDRIP(dest, mask); if(route.len == 32 && !mask.equals("255.255.255.255")) { @@ -468,6 +522,15 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac mRoutesv6.add(extra); } + public void setMtu(int mtu) { + mMtu=mtu; + } + + public void setLocalIP(CIDRIP cdrip) + { + mLocalIP=cdrip; + } + public void setLocalIP(String local, String netmask,int mtu, String mode) { mLocalIP = new CIDRIP(local, netmask); @@ -477,7 +540,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // get the netmask as IP long netint = CIDRIP.getInt(netmask); if(Math.abs(netint - mLocalIP.getInt()) ==1) { - if(mode.equals("net30")) + if("net30".equals(mode)) mLocalIP.len=30; else mLocalIP.len=31; @@ -559,7 +622,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac } } - public OpenVpnManagementThread getManagementThread() { - return mManagementThread; + public OpenVPNMangement getManagement() { + return mManagement; } } diff --git a/src/de/blinkt/openvpn/ShowConfigFragment.java b/src/de/blinkt/openvpn/ShowConfigFragment.java index dae83438..c9c778df 100644 --- a/src/de/blinkt/openvpn/ShowConfigFragment.java +++ b/src/de/blinkt/openvpn/ShowConfigFragment.java @@ -17,21 +17,41 @@ public class ShowConfigFragment extends Fragment { public android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { String profileUUID = getArguments().getString(getActivity().getPackageName() + ".profileUUID"); - VpnProfile vp = ProfileManager.get(profileUUID); + final VpnProfile vp = ProfileManager.get(profileUUID); View v=inflater.inflate(R.layout.viewconfig, container,false); - TextView cv = (TextView) v.findViewById(R.id.configview); + final TextView cv = (TextView) v.findViewById(R.id.configview); int check=vp.checkProfile(getActivity()); if(check!=R.string.no_error_found) { cv.setText(check); configtext = getString(check); } - else { - String cfg=vp.getConfigFile(getActivity()); - configtext= cfg; - cv.setText(cfg); + else { + // Run in own Thread since Keystore does not like to be queried from the main thread + + cv.setText("Generating config..."); + startGenConfig(vp, cv); } return v; + } + + private void startGenConfig(final VpnProfile vp, final TextView cv) { + + new Thread() { + public void run() { + final String cfg=vp.getConfigFile(getActivity(),false); + configtext= cfg; + getActivity().runOnUiThread(new Runnable() { + + @Override + public void run() { + cv.setText(cfg); + } + }); + + + }; + }.start(); }; @Override diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index 37e9b2ff..ea034b55 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -9,6 +9,11 @@ import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateException; @@ -19,6 +24,11 @@ import java.util.Locale; import java.util.UUID; import java.util.Vector; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; + import org.spongycastle.util.io.pem.PemObject; import org.spongycastle.util.io.pem.PemWriter; @@ -30,6 +40,7 @@ import android.os.Build; import android.preference.PreferenceManager; import android.security.KeyChain; import android.security.KeyChainException; +import android.util.Base64; public class VpnProfile implements Serializable{ // Parcable @@ -112,9 +123,10 @@ public class VpnProfile implements Serializable{ static final String MINIVPN = "miniopenvpn"; - - - + static private native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException; + static { + System.loadLibrary("opvpnutil"); + } public void clearDefaults() { mServerName="unkown"; @@ -140,11 +152,6 @@ public class VpnProfile implements Serializable{ return '"' + escapedString + '"'; } - - static final String OVPNCONFIGCA = "android-ca.pem"; - static final String OVPNCONFIGUSERCERT = "android-user.pem"; - - public VpnProfile(String name) { mUuid = UUID.randomUUID(); mName = name; @@ -160,7 +167,7 @@ public class VpnProfile implements Serializable{ } - public String getConfigFile(Context context) + public String getConfigFile(Context context, boolean configForOvpn3) { File cacheDir= context.getCacheDir(); @@ -255,10 +262,13 @@ public class VpnProfile implements Serializable{ case VpnProfile.TYPE_USERPASS_KEYSTORE: cfg+="auth-user-pass\n"; case VpnProfile.TYPE_KEYSTORE: - cfg+="ca " + cacheDir.getAbsolutePath() + "/" + OVPNCONFIGCA + "\n"; - cfg+="cert " + cacheDir.getAbsolutePath() + "/" + OVPNCONFIGUSERCERT + "\n"; - cfg+="management-external-key\n"; - + if(!configForOvpn3) { + String[] ks =getKeyStoreCertificates(context); + cfg+="### From Keystore ####\n"; + cfg+="\n" + ks[0] + "\n"; + cfg+="\n" + ks[0] + "\n"; + cfg+="management-external-key\n"; + } break; case VpnProfile.TYPE_USERPASS: cfg+="auth-user-pass\n"; @@ -498,7 +508,7 @@ public class VpnProfile implements Serializable{ Intent intent = new Intent(context,OpenVpnService.class); if(mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { - if(!saveCertificates(context)) + if(getKeyStoreCertificates(context)==null) return null; } @@ -510,7 +520,7 @@ public class VpnProfile implements Serializable{ try { FileWriter cfg = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE); - cfg.write(getConfigFile(context)); + cfg.write(getConfigFile(context,false)); cfg.flush(); cfg.close(); } catch (IOException e) { @@ -520,7 +530,7 @@ public class VpnProfile implements Serializable{ return intent; } - private boolean saveCertificates(Context context) { + String[] getKeyStoreCertificates(Context context) { PrivateKey privateKey = null; X509Certificate[] cachain=null; try { @@ -553,27 +563,30 @@ public class VpnProfile implements Serializable{ } - FileWriter fout = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + VpnProfile.OVPNCONFIGCA); - PemWriter pw = new PemWriter(fout); + + StringWriter caout = new StringWriter(); + + PemWriter pw = new PemWriter(caout); for(X509Certificate cert:cachain) { pw.writeObject(new PemObject("CERTIFICATE", cert.getEncoded())); } - pw.close(); + + StringWriter certout = new StringWriter(); + + if(cachain.length>= 1){ X509Certificate usercert = cachain[0]; - FileWriter userout = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + VpnProfile.OVPNCONFIGUSERCERT); - - PemWriter upw = new PemWriter(userout); + PemWriter upw = new PemWriter(certout); upw.writeObject(new PemObject("CERTIFICATE", usercert.getEncoded())); upw.close(); } - - return true; + + return new String[] {caout.toString(),certout.toString()}; } catch (InterruptedException e) { e.printStackTrace(); } catch (FileNotFoundException e) { @@ -590,7 +603,7 @@ public class VpnProfile implements Serializable{ } } } - return false; + return null; } private Certificate getCacertFromFile() throws FileNotFoundException, CertificateException { CertificateFactory certFact = CertificateFactory.getInstance("X.509"); @@ -651,7 +664,7 @@ public class VpnProfile implements Serializable{ return null; } } - private boolean isUserPWAuth() { + boolean isUserPWAuth() { switch(mAuthenticationType) { case TYPE_USERPASS: case TYPE_USERPASS_CERTIFICATES: @@ -748,6 +761,89 @@ public class VpnProfile implements Serializable{ return mPrivateKey; } + public String getSignedData(String b64data) { + PrivateKey privkey = getKeystoreKey(); + Exception err =null; + + byte[] data = Base64.decode(b64data, Base64.DEFAULT); + + // The Jelly Bean *evil* Hack + // 4.2 implements the RSA/ECB/PKCS1PADDING in the OpenSSLprovider + if(Build.VERSION.SDK_INT==Build.VERSION_CODES.JELLY_BEAN){ + return processSignJellyBeans(privkey,data); + } + + + try{ + + + Cipher rsasinger = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); + + rsasinger.init(Cipher.ENCRYPT_MODE, privkey); + + byte[] signed_bytes = rsasinger.doFinal(data); + return Base64.encodeToString(signed_bytes, Base64.NO_WRAP); + + } catch (NoSuchAlgorithmException e){ + err =e; + } catch (InvalidKeyException e) { + err =e; + } catch (NoSuchPaddingException e) { + err =e; + } catch (IllegalBlockSizeException e) { + err =e; + } catch (BadPaddingException e) { + err =e; + } + if(err !=null) { + OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage()); + } + return null; + + } + + + private String processSignJellyBeans(PrivateKey privkey, byte[] data) { + Exception err =null; + try { + Method[] allm = privkey.getClass().getSuperclass().getDeclaredMethods(); + System.out.println(allm); + Method getKey = privkey.getClass().getSuperclass().getDeclaredMethod("getOpenSSLKey"); + getKey.setAccessible(true); + + // Real object type is OpenSSLKey + Object opensslkey = getKey.invoke(privkey); + + getKey.setAccessible(false); + + Method getPkeyContext = opensslkey.getClass().getDeclaredMethod("getPkeyContext"); + + // integer pointer to EVP_pkey + getPkeyContext.setAccessible(true); + int pkey = (Integer) getPkeyContext.invoke(opensslkey); + getPkeyContext.setAccessible(false); + + byte[] signed_bytes = rsasign(data, pkey); + return Base64.encodeToString(signed_bytes, Base64.NO_WRAP); + + } catch (NoSuchMethodException e) { + err=e; + } catch (IllegalArgumentException e) { + err=e; + } catch (IllegalAccessException e) { + err=e; + } catch (InvocationTargetException e) { + err=e; + } catch (InvalidKeyException e) { + err=e; + } + if(err !=null) { + OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage()); + } + return null; + + } + } -- cgit v1.2.3