summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgignore3
-rw-r--r--jni/Android.mk2
-rw-r--r--jni/Application.mk3
-rw-r--r--jni/jbcrypto.cpp4
-rw-r--r--ovpn3/Android.mk37
-rw-r--r--ovpn3/boostsrc/error_code.cpp430
-rw-r--r--res/xml/general_settings.xml7
-rw-r--r--src/de/blinkt/openvpn/CIDRIP.java6
-rw-r--r--src/de/blinkt/openvpn/OpenVPNThreadv3.java201
-rw-r--r--src/de/blinkt/openvpn/OpenVpnManagementThread.java89
-rw-r--r--src/de/blinkt/openvpn/OpenVpnService.java45
-rw-r--r--src/de/blinkt/openvpn/ShowConfigFragment.java32
-rw-r--r--src/de/blinkt/openvpn/VpnProfile.java149
13 files changed, 879 insertions, 129 deletions
diff --git a/.hgignore b/.hgignore
index 7a6193b8..eab1094c 100644
--- a/.hgignore
+++ b/.hgignore
@@ -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;
+
+ }
+
}