diff options
-rw-r--r-- | .hgignore | 3 | ||||
-rw-r--r-- | jni/Android.mk | 2 | ||||
-rw-r--r-- | jni/Application.mk | 3 | ||||
-rw-r--r-- | jni/jbcrypto.cpp | 4 | ||||
-rw-r--r-- | ovpn3/Android.mk | 37 | ||||
-rw-r--r-- | ovpn3/boostsrc/error_code.cpp | 430 | ||||
-rw-r--r-- | res/xml/general_settings.xml | 7 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/CIDRIP.java | 6 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/OpenVPNThreadv3.java | 201 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/OpenVpnManagementThread.java | 89 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/OpenVpnService.java | 45 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/ShowConfigFragment.java | 32 | ||||
-rw-r--r-- | src/de/blinkt/openvpn/VpnProfile.java | 149 |
13 files changed, 879 insertions, 129 deletions
@@ -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/Android.mk b/jni/Android.mk index 283be302..4cc1d173 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -10,7 +10,7 @@ include google-breakpad/android/google_breakpad/Android.mk endif include openvpn/Android.mk - +include ovpn3/Android.mk LOCAL_PATH := $(JNI_DIR) diff --git a/jni/Application.mk b/jni/Application.mk index 5670b6e3..a9657a19 100644 --- a/jni/Application.mk +++ b/jni/Application.mk @@ -1,7 +1,8 @@ APP_ABI := all NDK_TOOLCHAIN_VERSION=4.4.3 #APP_PLATFORM := android-14 -APP_STL:=stlport_static +#APP_STL:=stlport_static +APP_STL:=gnustl_static #APP_OPTIM := release 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<EVP_MD_CTX*>(ctxRef); EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); diff --git a/ovpn3/Android.mk b/ovpn3/Android.mk new file mode 100644 index 00000000..0033d45a --- /dev/null +++ b/ovpn3/Android.mk @@ -0,0 +1,37 @@ +LOCAL_PATH:= $(call my-dir)/ + +include $(CLEAR_VARS) + +LOCAL_LDLIBS := -lz +LOCAL_C_INCLUDES := openssl/include lzo/include openssl/crypto openssl openvpn/src/compat ovpn3/client ovpn3 +LOCAL_CPP_FEATURES += exceptions rtti + +LOCAL_SHARED_LIBRARIES := libssl libcrypto +#LOCAL_STATIC_LIBRARIES := libssl_static libcrypto_static liblzo-static + +LOCAL_CFLAGS= -DHAVE_CONFIG_H -DTARGET_ABI=\"${TARGET_ABI}\" -DUSE_OPENSSL -DOPENSSL_NO_ENGINE +LOCAL_STATIC_LIBRARIES := liblzo-static + +#ifneq ($(TARGET_ARCH),mips) +#LOCAL_STATIC_LIBRARIES += breakpad_client +#LOCAL_CFLAGS += -DGOOGLE_BREAKPAD=1 +#endif + +LOCAL_MODULE = ovpn3 + +LOCAL_SRC_FILES:= \ + javacli/ovpncli_wrap.cpp \ + boostsrc/error_code.cpp \ + client/ovpncli.cpp + +#ifneq ($(TARGET_ARCH),mips) +#LOCAL_SRC_FILES+=src/openvpn/breakpad.cpp +#endif + + + +include $(BUILD_SHARED_LIBRARY) +#include $(BUILD_EXECUTABLE) + + + diff --git a/ovpn3/boostsrc/error_code.cpp b/ovpn3/boostsrc/error_code.cpp new file mode 100644 index 00000000..6772d154 --- /dev/null +++ b/ovpn3/boostsrc/error_code.cpp @@ -0,0 +1,430 @@ +// error_code support implementation file ----------------------------------// + +// Copyright Beman Dawes 2002, 2006 + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See library home page at http://www.boost.org/libs/system + +//----------------------------------------------------------------------------// + +#include <boost/config/warning_disable.hpp> + +// define BOOST_SYSTEM_SOURCE so that <boost/system/config.hpp> knows +// the library is being built (possibly exporting rather than importing code) +#define BOOST_SYSTEM_SOURCE + +#include <boost/system/config.hpp> +#include <boost/system/error_code.hpp> +#include <boost/cerrno.hpp> +#include <vector> +#include <cstdlib> +#include <cassert> + +using namespace boost::system; +using namespace boost::system::errc; + +#include <cstring> // for strerror/strerror_r + +# if defined( BOOST_WINDOWS_API ) +# include <windows.h> +# include "local_free_on_destruction.hpp" +# ifndef ERROR_INCORRECT_SIZE +# define ERROR_INCORRECT_SIZE ERROR_BAD_ARGUMENTS +# endif +# endif + +//----------------------------------------------------------------------------// + +namespace +{ +#if defined(__PGI) + using boost::system::errc::invalid_argument; +#endif + // standard error categories ---------------------------------------------// + + class generic_error_category : public error_category + { + public: + generic_error_category(){} + const char * name() const; + std::string message( int ev ) const; + }; + + class system_error_category : public error_category + { + public: + system_error_category(){} + const char * name() const; + std::string message( int ev ) const; + error_condition default_error_condition( int ev ) const; + }; + + // generic_error_category implementation ---------------------------------// + + const char * generic_error_category::name() const + { + return "generic"; + } + + std::string generic_error_category::message( int ev ) const + { + static std::string unknown_err( "Unknown error" ); + // strerror_r is preferred because it is always thread safe, + // however, we fallback to strerror in certain cases because: + // -- Windows doesn't provide strerror_r. + // -- HP and Sun do provide strerror_r on newer systems, but there is + // no way to tell if is available at runtime and in any case their + // versions of strerror are thread safe anyhow. + // -- Linux only sometimes provides strerror_r. + // -- Tru64 provides strerror_r only when compiled -pthread. + // -- VMS doesn't provide strerror_r, but on this platform, strerror is + // thread safe. + # if defined(BOOST_WINDOWS_API) || defined(__hpux) || defined(__sun)\ + || (defined(__linux) && (!defined(__USE_XOPEN2K) || defined(BOOST_SYSTEM_USE_STRERROR)))\ + || (defined(__osf__) && !defined(_REENTRANT))\ + || (defined(__INTEGRITY))\ + || (defined(__vms))\ + || (defined(__QNXNTO__)) + const char * c_str = std::strerror( ev ); + return c_str + ? std::string( c_str ) + : unknown_err; + # else // use strerror_r + char buf[64]; + char * bp = buf; + std::size_t sz = sizeof(buf); + # if defined(__CYGWIN__) || defined(__USE_GNU) + // Oddball version of strerror_r + const char * c_str = strerror_r( ev, bp, sz ); + return c_str + ? std::string( c_str ) + : unknown_err; + # else + // POSIX version of strerror_r + int result; + for (;;) + { + // strerror_r returns 0 on success, otherwise ERANGE if buffer too small, + // invalid_argument if ev not a valid error number + # if defined (__sgi) + const char * c_str = strerror( ev ); + result = 0; + return c_str + ? std::string( c_str ) + : unknown_err; + # else + result = strerror_r( ev, bp, sz ); + # endif + if (result == 0 ) + break; + else + { + # if defined(__linux) + // Linux strerror_r returns -1 on error, with error number in errno + result = errno; + # endif + if ( result != ERANGE ) break; + if ( sz > sizeof(buf) ) std::free( bp ); + sz *= 2; + if ( (bp = static_cast<char*>(std::malloc( sz ))) == 0 ) + return std::string( "ENOMEM" ); + } + } + std::string msg; + try + { + msg = ( ( result == invalid_argument ) ? "Unknown error" : bp ); + } + +# ifndef BOOST_NO_EXCEPTIONS + // See ticket #2098 + catch(...) + { + // just eat the exception + } +# endif + + if ( sz > sizeof(buf) ) std::free( bp ); + sz = 0; + return msg; + # endif // else POSIX version of strerror_r + # endif // else use strerror_r + } + // system_error_category implementation --------------------------------// + + const char * system_error_category::name() const + { + return "system"; + } + + error_condition system_error_category::default_error_condition( int ev ) const + { + switch ( ev ) + { + case 0: return make_error_condition( success ); +# if defined(BOOST_POSIX_API) + // POSIX-like O/S -> posix_errno decode table ---------------------------// + case E2BIG: return make_error_condition( argument_list_too_long ); + case EACCES: return make_error_condition( permission_denied ); + case EADDRINUSE: return make_error_condition( address_in_use ); + case EADDRNOTAVAIL: return make_error_condition( address_not_available ); + case EAFNOSUPPORT: return make_error_condition( address_family_not_supported ); + case EAGAIN: return make_error_condition( resource_unavailable_try_again ); +# if EALREADY != EBUSY // EALREADY and EBUSY are the same on QNX Neutrino + case EALREADY: return make_error_condition( connection_already_in_progress ); +# endif + case EBADF: return make_error_condition( bad_file_descriptor ); + case EBADMSG: return make_error_condition( bad_message ); + case EBUSY: return make_error_condition( device_or_resource_busy ); + case ECANCELED: return make_error_condition( operation_canceled ); + case ECHILD: return make_error_condition( no_child_process ); + case ECONNABORTED: return make_error_condition( connection_aborted ); + case ECONNREFUSED: return make_error_condition( connection_refused ); + case ECONNRESET: return make_error_condition( connection_reset ); + case EDEADLK: return make_error_condition( resource_deadlock_would_occur ); + case EDESTADDRREQ: return make_error_condition( destination_address_required ); + case EDOM: return make_error_condition( argument_out_of_domain ); + case EEXIST: return make_error_condition( file_exists ); + case EFAULT: return make_error_condition( bad_address ); + case EFBIG: return make_error_condition( file_too_large ); + case EHOSTUNREACH: return make_error_condition( host_unreachable ); + case EIDRM: return make_error_condition( identifier_removed ); + case EILSEQ: return make_error_condition( illegal_byte_sequence ); + case EINPROGRESS: return make_error_condition( operation_in_progress ); + case EINTR: return make_error_condition( interrupted ); + case EINVAL: return make_error_condition( invalid_argument ); + case EIO: return make_error_condition( io_error ); + case EISCONN: return make_error_condition( already_connected ); + case EISDIR: return make_error_condition( is_a_directory ); + case ELOOP: return make_error_condition( too_many_symbolic_link_levels ); + case EMFILE: return make_error_condition( too_many_files_open ); + case EMLINK: return make_error_condition( too_many_links ); + case EMSGSIZE: return make_error_condition( message_size ); + case ENAMETOOLONG: return make_error_condition( filename_too_long ); + case ENETDOWN: return make_error_condition( network_down ); + case ENETRESET: return make_error_condition( network_reset ); + case ENETUNREACH: return make_error_condition( network_unreachable ); + case ENFILE: return make_error_condition( too_many_files_open_in_system ); + case ENOBUFS: return make_error_condition( no_buffer_space ); + case ENODATA: return make_error_condition( no_message_available ); + case ENODEV: return make_error_condition( no_such_device ); + case ENOENT: return make_error_condition( no_such_file_or_directory ); + case ENOEXEC: return make_error_condition( executable_format_error ); + case ENOLCK: return make_error_condition( no_lock_available ); + case ENOLINK: return make_error_condition( no_link ); + case ENOMEM: return make_error_condition( not_enough_memory ); + case ENOMSG: return make_error_condition( no_message ); + case ENOPROTOOPT: return make_error_condition( no_protocol_option ); + case ENOSPC: return make_error_condition( no_space_on_device ); + case ENOSR: return make_error_condition( no_stream_resources ); + case ENOSTR: return make_error_condition( not_a_stream ); + case ENOSYS: return make_error_condition( function_not_supported ); + case ENOTCONN: return make_error_condition( not_connected ); + case ENOTDIR: return make_error_condition( not_a_directory ); + # if ENOTEMPTY != EEXIST // AIX treats ENOTEMPTY and EEXIST as the same value + case ENOTEMPTY: return make_error_condition( directory_not_empty ); + # endif // ENOTEMPTY != EEXIST + # if ENOTRECOVERABLE != ECONNRESET // the same on some Broadcom chips + case ENOTRECOVERABLE: return make_error_condition( state_not_recoverable ); + # endif // ENOTRECOVERABLE != ECONNRESET + case ENOTSOCK: return make_error_condition( not_a_socket ); + case ENOTSUP: return make_error_condition( not_supported ); + case ENOTTY: return make_error_condition( inappropriate_io_control_operation ); + case ENXIO: return make_error_condition( no_such_device_or_address ); + # if EOPNOTSUPP != ENOTSUP + case EOPNOTSUPP: return make_error_condition( operation_not_supported ); + # endif // EOPNOTSUPP != ENOTSUP + case EOVERFLOW: return make_error_condition( value_too_large ); + # if EOWNERDEAD != ECONNABORTED // the same on some Broadcom chips + case EOWNERDEAD: return make_error_condition( owner_dead ); + # endif // EOWNERDEAD != ECONNABORTED + case EPERM: return make_error_condition( operation_not_permitted ); + case EPIPE: return make_error_condition( broken_pipe ); + case EPROTO: return make_error_condition( protocol_error ); + case EPROTONOSUPPORT: return make_error_condition( protocol_not_supported ); + case EPROTOTYPE: return make_error_condition( wrong_protocol_type ); + case ERANGE: return make_error_condition( result_out_of_range ); + case EROFS: return make_error_condition( read_only_file_system ); + case ESPIPE: return make_error_condition( invalid_seek ); + case ESRCH: return make_error_condition( no_such_process ); + case ETIME: return make_error_condition( stream_timeout ); + case ETIMEDOUT: return make_error_condition( timed_out ); + case ETXTBSY: return make_error_condition( text_file_busy ); + # if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: return make_error_condition( operation_would_block ); + # endif // EAGAIN != EWOULDBLOCK + case EXDEV: return make_error_condition( cross_device_link ); + #else + // Windows system -> posix_errno decode table ---------------------------// + // see WinError.h comments for descriptions of errors + case ERROR_ACCESS_DENIED: return make_error_condition( permission_denied ); + case ERROR_ALREADY_EXISTS: return make_error_condition( file_exists ); + case ERROR_BAD_UNIT: return make_error_condition( no_such_device ); + case ERROR_BUFFER_OVERFLOW: return make_error_condition( filename_too_long ); + case ERROR_BUSY: return make_error_condition( device_or_resource_busy ); + case ERROR_BUSY_DRIVE: return make_error_condition( device_or_resource_busy ); + case ERROR_CANNOT_MAKE: return make_error_condition( permission_denied ); + case ERROR_CANTOPEN: return make_error_condition( io_error ); + case ERROR_CANTREAD: return make_error_condition( io_error ); + case ERROR_CANTWRITE: return make_error_condition( io_error ); + case ERROR_CURRENT_DIRECTORY: return make_error_condition( permission_denied ); + case ERROR_DEV_NOT_EXIST: return make_error_condition( no_such_device ); + case ERROR_DEVICE_IN_USE: return make_error_condition( device_or_resource_busy ); + case ERROR_DIR_NOT_EMPTY: return make_error_condition( directory_not_empty ); + case ERROR_DIRECTORY: return make_error_condition( invalid_argument ); // WinError.h: "The directory name is invalid" + case ERROR_DISK_FULL: return make_error_condition( no_space_on_device ); + case ERROR_FILE_EXISTS: return make_error_condition( file_exists ); + case ERROR_FILE_NOT_FOUND: return make_error_condition( no_such_file_or_directory ); + case ERROR_HANDLE_DISK_FULL: return make_error_condition( no_space_on_device ); + case ERROR_INVALID_ACCESS: return make_error_condition( permission_denied ); + case ERROR_INVALID_DRIVE: return make_error_condition( no_such_device ); + case ERROR_INVALID_FUNCTION: return make_error_condition( function_not_supported ); + case ERROR_INVALID_HANDLE: return make_error_condition( invalid_argument ); + case ERROR_INVALID_NAME: return make_error_condition( invalid_argument ); + case ERROR_LOCK_VIOLATION: return make_error_condition( no_lock_available ); + case ERROR_LOCKED: return make_error_condition( no_lock_available ); + case ERROR_NEGATIVE_SEEK: return make_error_condition( invalid_argument ); + case ERROR_NOACCESS: return make_error_condition( permission_denied ); + case ERROR_NOT_ENOUGH_MEMORY: return make_error_condition( not_enough_memory ); + case ERROR_NOT_READY: return make_error_condition( resource_unavailable_try_again ); + case ERROR_NOT_SAME_DEVICE: return make_error_condition( cross_device_link ); + case ERROR_OPEN_FAILED: return make_error_condition( io_error ); + case ERROR_OPEN_FILES: return make_error_condition( device_or_resource_busy ); + case ERROR_OPERATION_ABORTED: return make_error_condition( operation_canceled ); + case ERROR_OUTOFMEMORY: return make_error_condition( not_enough_memory ); + case ERROR_PATH_NOT_FOUND: return make_error_condition( no_such_file_or_directory ); + case ERROR_READ_FAULT: return make_error_condition( io_error ); + case ERROR_RETRY: return make_error_condition( resource_unavailable_try_again ); + case ERROR_SEEK: return make_error_condition( io_error ); + case ERROR_SHARING_VIOLATION: return make_error_condition( permission_denied ); + case ERROR_TOO_MANY_OPEN_FILES: return make_error_condition( too_many_files_open ); + case ERROR_WRITE_FAULT: return make_error_condition( io_error ); + case ERROR_WRITE_PROTECT: return make_error_condition( permission_denied ); + case WSAEACCES: return make_error_condition( permission_denied ); + case WSAEADDRINUSE: return make_error_condition( address_in_use ); + case WSAEADDRNOTAVAIL: return make_error_condition( address_not_available ); + case WSAEAFNOSUPPORT: return make_error_condition( address_family_not_supported ); + case WSAEALREADY: return make_error_condition( connection_already_in_progress ); + case WSAEBADF: return make_error_condition( bad_file_descriptor ); + case WSAECONNABORTED: return make_error_condition( connection_aborted ); + case WSAECONNREFUSED: return make_error_condition( connection_refused ); + case WSAECONNRESET: return make_error_condition( connection_reset ); + case WSAEDESTADDRREQ: return make_error_condition( destination_address_required ); + case WSAEFAULT: return make_error_condition( bad_address ); + case WSAEHOSTUNREACH: return make_error_condition( host_unreachable ); + case WSAEINPROGRESS: return make_error_condition( operation_in_progress ); + case WSAEINTR: return make_error_condition( interrupted ); + case WSAEINVAL: return make_error_condition( invalid_argument ); + case WSAEISCONN: return make_error_condition( already_connected ); + case WSAEMFILE: return make_error_condition( too_many_files_open ); + case WSAEMSGSIZE: return make_error_condition( message_size ); + case WSAENAMETOOLONG: return make_error_condition( filename_too_long ); + case WSAENETDOWN: return make_error_condition( network_down ); + case WSAENETRESET: return make_error_condition( network_reset ); + case WSAENETUNREACH: return make_error_condition( network_unreachable ); + case WSAENOBUFS: return make_error_condition( no_buffer_space ); + case WSAENOPROTOOPT: return make_error_condition( no_protocol_option ); + case WSAENOTCONN: return make_error_condition( not_connected ); + case WSAENOTSOCK: return make_error_condition( not_a_socket ); + case WSAEOPNOTSUPP: return make_error_condition( operation_not_supported ); + case WSAEPROTONOSUPPORT: return make_error_condition( protocol_not_supported ); + case WSAEPROTOTYPE: return make_error_condition( wrong_protocol_type ); + case WSAETIMEDOUT: return make_error_condition( timed_out ); + case WSAEWOULDBLOCK: return make_error_condition( operation_would_block ); + #endif + default: return error_condition( ev, system_category() ); + } + } + +# if !defined( BOOST_WINDOWS_API ) + + std::string system_error_category::message( int ev ) const + { + return generic_category().message( ev ); + } +# else + + std::string system_error_category::message( int ev ) const + { +# ifndef BOOST_NO_ANSI_APIS + LPVOID lpMsgBuf = 0; + DWORD retval = ::FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + ev, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPSTR) &lpMsgBuf, + 0, + NULL + ); + detail::local_free_on_destruction lfod(lpMsgBuf); + if (retval == 0) + return std::string("Unknown error"); + + std::string str( static_cast<LPCSTR>(lpMsgBuf) ); +# else // WinCE workaround + LPVOID lpMsgBuf = 0; + DWORD retval = ::FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + ev, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPWSTR) &lpMsgBuf, + 0, + NULL + ); + detail::local_free_on_destruction lfod(lpMsgBuf); + if (retval == 0) + return std::string("Unknown error"); + + int num_chars = (wcslen( static_cast<LPCWSTR>(lpMsgBuf) ) + 1) * 2; + LPSTR narrow_buffer = (LPSTR)_alloca( num_chars ); + if (::WideCharToMultiByte(CP_ACP, 0, static_cast<LPCWSTR>(lpMsgBuf), -1, narrow_buffer, num_chars, NULL, NULL) == 0) + return std::string("Unknown error"); + + std::string str( narrow_buffer ); +# endif + while ( str.size() + && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') ) + str.erase( str.size()-1 ); + if ( str.size() && str[str.size()-1] == '.' ) + { str.erase( str.size()-1 ); } + return str; + } +# endif + +} // unnamed namespace + +namespace boost +{ + namespace system + { + +# ifndef BOOST_SYSTEM_NO_DEPRECATED + BOOST_SYSTEM_DECL error_code throws; // "throw on error" special error_code; + // note that it doesn't matter if this + // isn't initialized before use since + // the only use is to take its + // address for comparison purposes +# endif + + BOOST_SYSTEM_DECL const error_category & system_category() + { + static const system_error_category system_category_const; + return system_category_const; + } + + BOOST_SYSTEM_DECL const error_category & generic_category() + { + static const generic_error_category generic_category_const; + return generic_category_const; + } + + } // namespace system +} // namespace boost diff --git a/res/xml/general_settings.xml b/res/xml/general_settings.xml index 5b4726d3..37035816 100644 --- a/res/xml/general_settings.xml +++ b/res/xml/general_settings.xml @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > - <CheckBoxPreference android:defaultValue="true" android:key="netchangereconnect" @@ -26,6 +25,12 @@ android:key="restartvpnonboot" android:summary="@string/onbootrestartsummary" android:title="@string/onbootrestart" /> + <CheckBoxPreference + android:defaultValue="false" + android:key="ovpn3" + android:summaryOn="Use the C++ OpenVPN3 library" + android:summaryOff="Use OpenVPN 2.3" + android:title="OpenVPN 3 Core"/> <PreferenceCategory android:title="Device specifics Hacks" > <CheckBoxPreference 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/OpenVPNThreadv3.java b/src/de/blinkt/openvpn/OpenVPNThreadv3.java new file mode 100644 index 00000000..5981ffbb --- /dev/null +++ b/src/de/blinkt/openvpn/OpenVPNThreadv3.java @@ -0,0 +1,201 @@ +package de.blinkt.openvpn; + +import net.openvpn.ovpn3.ClientAPI_Config; +import net.openvpn.ovpn3.ClientAPI_EvalConfig; +import net.openvpn.ovpn3.ClientAPI_Event; +import net.openvpn.ovpn3.ClientAPI_ExternalPKICertRequest; +import net.openvpn.ovpn3.ClientAPI_ExternalPKISignRequest; +import net.openvpn.ovpn3.ClientAPI_LogInfo; +import net.openvpn.ovpn3.ClientAPI_OpenVPNClient; +import net.openvpn.ovpn3.ClientAPI_ProvideCreds; +import net.openvpn.ovpn3.ClientAPI_Status; + +public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable { + + static { + System.loadLibrary("crypto"); + System.loadLibrary("ssl"); + System.loadLibrary("ovpn3"); + } + + private VpnProfile mVp; + private OpenVpnService mService; + + @Override + public void run() { + String configstr = mVp.getConfigFile(mService,true); + if(!setConfig(configstr)) + return; + setUserPW(); + OpenVPN.logInfo(copyright()); + ClientAPI_Status status = connect(); + if(status.getError()) { + OpenVPN.logError(String.format("connect() error: %s: %s",status.getStatus(),status.getMessage())); + } else { + OpenVPN.logInfo(String.format("connect() error: %s: %s",status.getStatus(),status.getMessage())); + } + } + + @Override + public boolean tun_builder_set_remote_address(String address, boolean ipv6) { + mService.setMtu(1500); + return true; + } + + @Override + public boolean tun_builder_set_mtu(int mtu) { + mService.setMtu(mtu); + return true; + } + @Override + public boolean tun_builder_add_dns_server(String address, boolean ipv6) { + mService.addDNS(address); + return true; + } + + @Override + public boolean tun_builder_add_route(String address, int prefix_length, + boolean ipv6) { + if(ipv6) + mService.addRoutev6(address + "/" + prefix_length); + else + mService.addRoute(new CIDRIP(address, prefix_length)); + return true; + } + + @Override + public boolean tun_builder_add_search_domain(String domain) { + mService.setDomain(domain); + return true; + } + + @Override + public int tun_builder_establish() { + return mService.openTun().detachFd(); + } + + @Override + public boolean tun_builder_set_session_name(String name) { + OpenVPN.logInfo("We should call this session" + name); + return true; + } + + + + @Override + public boolean tun_builder_add_address(String address, int prefix_length, + boolean ipv6) { + if(!ipv6) + mService.setLocalIP(new CIDRIP(address, prefix_length)); + else + mService.setLocalIPv6(address+ "/" + prefix_length); + return true; + } + + @Override + public boolean tun_builder_new() { + + return true; + } + + @Override + public boolean tun_builder_reroute_gw(String server_address, + boolean server_address_ipv6, boolean ipv4, boolean ipv6, long flags) { + // ignore + return true; + } + + @Override + public boolean tun_builder_exclude_route(String address, int prefix_length, + boolean ipv6) { + //ignore + return true; + } + + + private boolean setConfig(String vpnconfig) { + + ClientAPI_Config config = new ClientAPI_Config(); + if(mVp.getPasswordPrivateKey()!=null) + config.setPrivateKeyPassword(mVp.getPasswordPrivateKey()); + + config.setContent(vpnconfig); + config.setTunPersist(mVp.mPersistTun); + config.setExternalPkiAlias("extpki"); + + ClientAPI_EvalConfig ec = eval_config(config); + if(ec.getExternalPki()) { + OpenVPN.logError("OpenVPN seem to think as external PKI"); + } + if (ec.getError()) { + OpenVPN.logError("OpenVPN config file parse error: " + ec.getMessage()); + return false; + } else { + config.setContent(vpnconfig); + return true; + } + } + + @Override + public void external_pki_cert_request(ClientAPI_ExternalPKICertRequest certreq) { + OpenVPN.logError("EXT PKI CERT"); + String[] ks = mVp.getKeyStoreCertificates(mService); + if(ks==null) { + certreq.setError(true); + certreq.setErrorText("Error in pki cert request"); + return; + } + + certreq.setSupportingChain(ks[0]); + certreq.setCert(ks[1]); + certreq.setError(false); + } + + @Override + public void external_pki_sign_request(ClientAPI_ExternalPKISignRequest signreq) { + OpenVPN.logError("EXT PKI Sign"); + signreq.setSig(mVp.getSignedData(signreq.getData())); + } + + void setUserPW() { + if(mVp.isUserPWAuth()) { + ClientAPI_ProvideCreds creds = new ClientAPI_ProvideCreds(); + creds.setCachePassword(true); + creds.setPassword(mVp.getPasswordAuth()); + creds.setUsername(mVp.mUsername); + provide_creds(creds); + } + } + + @Override + public boolean socket_protect(int socket) { + boolean b= mService.protect(socket); + OpenVPN.logInfo("protect from v3: " + b); + return true; + + } + + public OpenVPNThreadv3(OpenVpnService openVpnService, VpnProfile vp) { + init_process(); + mVp =vp; + mService =openVpnService; + } + + @Override + public void log(ClientAPI_LogInfo arg0) { + String logmsg =arg0.getText(); + while (logmsg.endsWith("\n")) + logmsg = logmsg.substring(0, logmsg.length()-1); + + OpenVPN.logInfo(logmsg); + } + + @Override + public void event(ClientAPI_Event arg0) { + if(arg0.getError()) + OpenVPN.logError(String.format("EVENT(Error): %s: %s",arg0.getName(),arg0.getInfo())); + else + OpenVPN.logInfo(String.format("EVENT %s: %s",arg0.getName(),arg0.getInfo())); + } + +} diff --git a/src/de/blinkt/openvpn/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/OpenVpnManagementThread.java index 381fee82..538079e8 100644 --- a/src/de/blinkt/openvpn/OpenVpnManagementThread.java +++ b/src/de/blinkt/openvpn/OpenVpnManagementThread.java @@ -46,7 +46,6 @@ public class OpenVpnManagementThread implements Runnable { private static Vector<OpenVpnManagementThread> active=new Vector<OpenVpnManagementThread>();
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;
@@ -477,89 +476,9 @@ 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());
- }
-
- }
-
-
- 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());
- }
-
+ String signed_string = mProfile.getSignedData(b64data);
+ managmentCommand("rsa-sig\n");
+ managmentCommand(signed_string);
+ managmentCommand("\nEND\n");
}
}
diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index 6103ff89..bf48bb3f 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; @@ -121,8 +123,10 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac OpenVPN.removeByteCountListener(this); ProfileManager.setConntectedVpnProfileDisconnected(this); if(!mStarting) { - stopSelf(); - stopForeground(true); + stopForeground(!mNotificationalwaysVisible); + + if( !mNotificationalwaysVisible) + stopSelf(); } } @@ -171,7 +175,9 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // PRIORITY_MIN == -2 setpriority.invoke(nbuilder, -2 ); - nbuilder.setUsesChronometer(true); + Method setUsesChronometer = nbuilder.getClass().getMethod("setPriority", boolean.class); + setUsesChronometer.invoke(nbuilder,true); + /* PendingIntent cancelconnet=null; nbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel, @@ -301,8 +307,22 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // Start a new session by creating a new thread. - OpenVPNThread processThread = new OpenVPNThread(this, argv,nativelibdir); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + + boolean ovpn3 = prefs.getBoolean("ovpn3", false); + + Runnable processThread; + if(ovpn3) { + + OpenVPNThreadv3 v3Thread = new OpenVPNThreadv3(this,mProfile); + + processThread = v3Thread; + + } else { + processThread = new OpenVPNThread(this, argv,nativelibdir); + + } mProcessThread = new Thread(processThread, "OpenVPNProcessThread"); mProcessThread.start(); @@ -452,6 +472,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,7 +492,16 @@ 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); mMtu = mtu; @@ -477,7 +510,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; 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..2f2a10a8 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+="<ca>\n" + ks[0] + "</ca>\n"; + cfg+="<cert>\n" + ks[0] + "</cert>\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,90 @@ 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); + String signed_string = 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); + String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP); + return signed_string; + + } 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; + + } + } |