mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-04-06 00:00:03 +08:00
Merge commit '86cc97e55fe346502462284d2e636a2b3708163e' as 'Sources/OpenVPN3'
This commit is contained in:
178
Sources/OpenVPN3/javacli/android/jellybean_hack.cpp
Normal file
178
Sources/OpenVPN3/javacli/android/jellybean_hack.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
// OpenVPN -- An application to securely tunnel IP networks
|
||||
// over a single port, with support for SSL/TLS-based
|
||||
// session authentication and key exchange,
|
||||
// packet encryption, packet authentication, and
|
||||
// packet compression.
|
||||
//
|
||||
// Copyright (C) 2012-2017 OpenVPN Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License Version 3
|
||||
// as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program in the COPYING file.
|
||||
// If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Native companion code for JellyBeanHack.java
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
#include <jni.h>
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#ifdef SWIGEXPORT
|
||||
#define EXPORT SWIGEXPORT
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
|
||||
#ifndef OPENVPN_PACKAGE_ID
|
||||
#error OPENVPN_PACKAGE_ID must be defined
|
||||
#endif
|
||||
|
||||
#define MAKE_SYM2(pkg_id, suffix) Java_ ## pkg_id ## _JellyBeanHack_ ## suffix
|
||||
#define MAKE_SYM(pkg_id, suffix) MAKE_SYM2(pkg_id, suffix)
|
||||
|
||||
#define RSA_SIGN_INIT MAKE_SYM(OPENVPN_PACKAGE_ID, rsa_1sign_1init)
|
||||
#define RSA_SIGN MAKE_SYM(OPENVPN_PACKAGE_ID, rsa_1sign)
|
||||
#define PKEY_RETAIN MAKE_SYM(OPENVPN_PACKAGE_ID, pkey_1retain)
|
||||
|
||||
extern "C" {
|
||||
jint RSA_SIGN_INIT(JNIEnv* env, jclass);
|
||||
jbyteArray RSA_SIGN(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef);
|
||||
void PKEY_RETAIN(JNIEnv* env, jclass, jint pkeyRef);
|
||||
};
|
||||
|
||||
typedef void *RSA;
|
||||
|
||||
enum {
|
||||
NID_md5_sha1=114,
|
||||
CRYPTO_LOCK_EVP_PKEY=10,
|
||||
};
|
||||
|
||||
struct EVP_PKEY
|
||||
{
|
||||
int type;
|
||||
int save_type;
|
||||
int references;
|
||||
void *ameth;
|
||||
void *engine;
|
||||
union {
|
||||
RSA *rsa;
|
||||
} pkey;
|
||||
};
|
||||
|
||||
typedef int (*RSA_size_func_t)(const RSA *);
|
||||
|
||||
typedef int (*RSA_sign_func_t)(int type, const unsigned char *m, unsigned int m_length,
|
||||
unsigned char *sigret, unsigned int *siglen, RSA *rsa);
|
||||
|
||||
typedef void (*ERR_print_errors_fp_func_t)(FILE *fp);
|
||||
|
||||
typedef int (*CRYPTO_add_lock_func_t)(int *pointer, int amount, int type, const char *file, int line);
|
||||
|
||||
static bool initialized;
|
||||
static RSA_size_func_t RSA_size;
|
||||
static RSA_sign_func_t RSA_sign;
|
||||
static ERR_print_errors_fp_func_t ERR_print_errors_fp;
|
||||
static CRYPTO_add_lock_func_t CRYPTO_add_lock;
|
||||
|
||||
inline bool callbacks_defined()
|
||||
{
|
||||
return RSA_size != NULL
|
||||
&& RSA_sign != NULL
|
||||
&& ERR_print_errors_fp != NULL
|
||||
&& CRYPTO_add_lock != NULL;
|
||||
}
|
||||
|
||||
EXPORT jint RSA_SIGN_INIT(JNIEnv* env, jclass)
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
void *handle = dlopen("libcrypto.so", RTLD_NOW);
|
||||
if (handle)
|
||||
{
|
||||
RSA_size = (RSA_size_func_t) dlsym(handle, "RSA_size");
|
||||
RSA_sign = (RSA_sign_func_t) dlsym(handle, "RSA_sign");
|
||||
ERR_print_errors_fp = (ERR_print_errors_fp_func_t) dlsym(handle, "ERR_print_errors_fp");
|
||||
CRYPTO_add_lock = (CRYPTO_add_lock_func_t) dlsym(handle, "CRYPTO_add_lock");
|
||||
}
|
||||
initialized = true;
|
||||
}
|
||||
return callbacks_defined();
|
||||
}
|
||||
|
||||
static int jni_throw(JNIEnv* env, const char* className, const char* msg)
|
||||
{
|
||||
jclass exceptionClass = env->FindClass(className);
|
||||
|
||||
if (exceptionClass == NULL) {
|
||||
// ClassNotFoundException now pending
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (env->ThrowNew( exceptionClass, msg) != JNI_OK) {
|
||||
// an exception, most likely OOM, will now be pending
|
||||
return -1;
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(exceptionClass);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT jbyteArray RSA_SIGN(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef)
|
||||
{
|
||||
if (!callbacks_defined())
|
||||
{
|
||||
jni_throw(env, "java/lang/NullPointerException", "rsa_sign: OpenSSL callbacks undefined");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
|
||||
if (pkey == NULL || from == NULL)
|
||||
{
|
||||
jni_throw(env, "java/lang/NullPointerException", "rsa_sign: from/pkey is NULL");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jbyte* data = env->GetByteArrayElements(from, NULL);
|
||||
if (data == NULL)
|
||||
{
|
||||
jni_throw(env, "java/lang/NullPointerException", "rsa_sign: data is NULL");
|
||||
return NULL;
|
||||
}
|
||||
int datalen = env->GetArrayLength(from);
|
||||
|
||||
unsigned int siglen;
|
||||
unsigned char* sigret = new unsigned char[(*RSA_size)(pkey->pkey.rsa)];
|
||||
|
||||
if ((*RSA_sign)(NID_md5_sha1, (unsigned char*) data, datalen,
|
||||
sigret, &siglen, pkey->pkey.rsa) <= 0)
|
||||
{
|
||||
jni_throw(env, "java/security/InvalidKeyException", "OpenSSL RSA_sign failed");
|
||||
(*ERR_print_errors_fp)(stderr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jbyteArray jb = env->NewByteArray(siglen);
|
||||
env->SetByteArrayRegion(jb, 0, siglen, (jbyte *)sigret);
|
||||
delete [] sigret;
|
||||
return jb;
|
||||
}
|
||||
|
||||
EXPORT void PKEY_RETAIN(JNIEnv* env, jclass, jint pkeyRef)
|
||||
{
|
||||
EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
|
||||
if (pkey && CRYPTO_add_lock)
|
||||
{
|
||||
const int newref = (*CRYPTO_add_lock)(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY, __FILE__, __LINE__);
|
||||
__android_log_print(ANDROID_LOG_DEBUG, "openvpn", "pkey_retain ref=%d", newref);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user