| /* Copyright 2000-2005 The Apache Software Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * |
| * @author Mladen Turk |
| * @version $Revision$, $Date$ |
| */ |
| |
| #include "tcn.h" |
| #include "apr_file_io.h" |
| #include "apr_thread_mutex.h" |
| #include "apr_atomic.h" |
| #include "apr_poll.h" |
| |
| #ifdef HAVE_OPENSSL |
| #include "ssl_private.h" |
| |
| static int ssl_initialized = 0; |
| extern apr_pool_t *tcn_global_pool; |
| |
| ENGINE *tcn_ssl_engine = NULL; |
| void *SSL_temp_keys[SSL_TMP_KEY_MAX]; |
| tcn_pass_cb_t tcn_password_callback; |
| |
| /* |
| * Handle the Temporary RSA Keys and DH Params |
| */ |
| |
| #define SSL_TMP_KEY_FREE(type, idx) \ |
| if (SSL_temp_keys[idx]) { \ |
| type##_free((type *)SSL_temp_keys[idx]); \ |
| SSL_temp_keys[idx] = NULL; \ |
| } else (void)(0) |
| |
| #define SSL_TMP_KEYS_FREE(type) \ |
| SSL_TMP_KEY_FREE(type, SSL_TMP_KEY_##type##_512); \ |
| SSL_TMP_KEY_FREE(type, SSL_TMP_KEY_##type##_1024); \ |
| SSL_TMP_KEY_FREE(type, SSL_TMP_KEY_##type##_2048); \ |
| SSL_TMP_KEY_FREE(type, SSL_TMP_KEY_##type##_4096) |
| |
| #define SSL_TMP_KEY_INIT_RSA(bits) \ |
| ssl_tmp_key_init_rsa(bits, SSL_TMP_KEY_RSA_##bits) |
| |
| #define SSL_TMP_KEY_INIT_DH(bits) \ |
| ssl_tmp_key_init_dh(bits, SSL_TMP_KEY_DH_##bits) |
| |
| #define SSL_TMP_KEYS_INIT(R) \ |
| SSL_temp_keys[SSL_TMP_KEY_RSA_2048] = NULL; \ |
| SSL_temp_keys[SSL_TMP_KEY_RSA_4096] = NULL; \ |
| R |= SSL_TMP_KEY_INIT_RSA(512); \ |
| R |= SSL_TMP_KEY_INIT_RSA(1024); \ |
| R |= SSL_TMP_KEY_INIT_DH(512); \ |
| R |= SSL_TMP_KEY_INIT_DH(1024); \ |
| R |= SSL_TMP_KEY_INIT_DH(2048); \ |
| R |= SSL_TMP_KEY_INIT_DH(4096) |
| |
| static int ssl_tmp_key_init_rsa(int bits, int idx) |
| { |
| if (!(SSL_temp_keys[idx] = |
| RSA_generate_key(bits, RSA_F4, NULL, NULL))) |
| return 1; |
| else |
| return 0; |
| } |
| |
| static int ssl_tmp_key_init_dh(int bits, int idx) |
| { |
| if (!(SSL_temp_keys[idx] = |
| SSL_dh_get_tmp_param(bits))) |
| return 1; |
| else |
| return 0; |
| } |
| |
| |
| TCN_IMPLEMENT_CALL(jint, SSL, version)(TCN_STDARGS) |
| { |
| UNREFERENCED_STDARGS; |
| return OPENSSL_VERSION_NUMBER; |
| } |
| |
| TCN_IMPLEMENT_CALL(jstring, SSL, versionString)(TCN_STDARGS) |
| { |
| UNREFERENCED(o); |
| return AJP_TO_JSTRING(OPENSSL_VERSION_TEXT); |
| } |
| |
| /* |
| * the various processing hooks |
| */ |
| static apr_status_t ssl_init_cleanup(void *data) |
| { |
| UNREFERENCED(data); |
| |
| if (!ssl_initialized) |
| return APR_SUCCESS; |
| ssl_initialized = 0; |
| |
| if (tcn_password_callback.cb.obj) { |
| TCN_UNLOAD_CLASS(tcn_password_callback.cb.env, |
| tcn_password_callback.cb.obj); |
| } |
| |
| SSL_TMP_KEYS_FREE(RSA); |
| SSL_TMP_KEYS_FREE(DH); |
| /* |
| * Try to kill the internals of the SSL library. |
| */ |
| #if OPENSSL_VERSION_NUMBER >= 0x00907001 |
| /* Corresponds to OPENSSL_load_builtin_modules(): |
| * XXX: borrowed from apps.h, but why not CONF_modules_free() |
| * which also invokes CONF_modules_finish()? |
| */ |
| CONF_modules_unload(1); |
| #endif |
| /* Corresponds to SSL_library_init: */ |
| EVP_cleanup(); |
| #if HAVE_ENGINE_LOAD_BUILTIN_ENGINES |
| ENGINE_cleanup(); |
| #endif |
| #if OPENSSL_VERSION_NUMBER >= 0x00907001 |
| CRYPTO_cleanup_all_ex_data(); |
| #endif |
| ERR_remove_state(0); |
| |
| /* Don't call ERR_free_strings here; ERR_load_*_strings only |
| * actually load the error strings once per process due to static |
| * variable abuse in OpenSSL. */ |
| |
| /* |
| * TODO: determine somewhere we can safely shove out diagnostics |
| * (when enabled) at this late stage in the game: |
| * CRYPTO_mem_leaks_fp(stderr); |
| */ |
| return APR_SUCCESS; |
| } |
| |
| #ifndef OPENSSL_NO_ENGINE |
| /* Try to load an engine in a shareable library */ |
| static ENGINE *ssl_try_load_engine(const char *engine) |
| { |
| ENGINE *e = ENGINE_by_id("dynamic"); |
| if (e) { |
| if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine, 0) |
| || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { |
| ENGINE_free(e); |
| e = NULL; |
| } |
| } |
| return e; |
| } |
| #endif |
| |
| /* |
| * To ensure thread-safetyness in OpenSSL |
| */ |
| |
| static apr_thread_mutex_t **ssl_lock_cs; |
| static int ssl_lock_num_locks; |
| |
| static void ssl_thread_lock(int mode, int type, |
| const char *file, int line) |
| { |
| UNREFERENCED(file); |
| UNREFERENCED(line); |
| if (type < ssl_lock_num_locks) { |
| if (mode & CRYPTO_LOCK) { |
| apr_thread_mutex_lock(ssl_lock_cs[type]); |
| } |
| else { |
| apr_thread_mutex_unlock(ssl_lock_cs[type]); |
| } |
| } |
| } |
| |
| static unsigned long ssl_thread_id(void) |
| { |
| /* OpenSSL needs this to return an unsigned long. On OS/390, the pthread |
| * id is a structure twice that big. Use the TCB pointer instead as a |
| * unique unsigned long. |
| */ |
| #ifdef __MVS__ |
| struct PSA { |
| char unmapped[540]; |
| unsigned long PSATOLD; |
| } *psaptr = 0; |
| |
| return psaptr->PSATOLD; |
| #else |
| return (unsigned long)(apr_os_thread_current()); |
| #endif |
| } |
| |
| static apr_status_t ssl_thread_cleanup(void *data) |
| { |
| UNREFERENCED(data); |
| CRYPTO_set_locking_callback(NULL); |
| CRYPTO_set_id_callback(NULL); |
| /* Let the registered mutex cleanups do their own thing |
| */ |
| return APR_SUCCESS; |
| } |
| |
| static void ssl_thread_setup(apr_pool_t *p) |
| { |
| int i; |
| |
| ssl_lock_num_locks = CRYPTO_num_locks(); |
| ssl_lock_cs = apr_palloc(p, ssl_lock_num_locks * sizeof(*ssl_lock_cs)); |
| |
| for (i = 0; i < ssl_lock_num_locks; i++) { |
| apr_thread_mutex_create(&(ssl_lock_cs[i]), |
| APR_THREAD_MUTEX_DEFAULT, p); |
| } |
| |
| CRYPTO_set_id_callback(ssl_thread_id); |
| CRYPTO_set_locking_callback(ssl_thread_lock); |
| |
| apr_pool_cleanup_register(p, NULL, ssl_thread_cleanup, |
| apr_pool_cleanup_null); |
| } |
| |
| static int ssl_rand_choosenum(int l, int h) |
| { |
| int i; |
| char buf[50]; |
| |
| apr_snprintf(buf, sizeof(buf), "%.0f", |
| (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l))); |
| i = atoi(buf)+1; |
| if (i < l) i = l; |
| if (i > h) i = h; |
| return i; |
| } |
| |
| static int ssl_rand_load_file(const char *file) |
| { |
| char buffer[APR_PATH_MAX]; |
| int n; |
| |
| if (file == NULL) |
| file = RAND_file_name(buffer, sizeof(buffer)); |
| else if ((n = RAND_egd(file)) > 0) { |
| return n; |
| } |
| if (file && (n = RAND_load_file(file, -1)) > 0) |
| return n; |
| else |
| return -1; |
| } |
| |
| /* |
| * writes a number of random bytes (currently 1024) to |
| * file which can be used to initialize the PRNG by calling |
| * RAND_load_file() in a later session |
| */ |
| static int ssl_rand_save_file(const char *file) |
| { |
| char buffer[APR_PATH_MAX]; |
| int n; |
| |
| if (file == NULL) |
| file = RAND_file_name(buffer, sizeof(buffer)); |
| else if ((n = RAND_egd(file)) > 0) { |
| return 0; |
| } |
| if (file == NULL || !RAND_write_file(file)) |
| return 0; |
| else |
| return 1; |
| } |
| |
| int SSL_rand_seed(const char *file) |
| { |
| unsigned char stackdata[256]; |
| static volatile apr_uint32_t counter = 0; |
| |
| if (ssl_rand_load_file(file) < 0) { |
| int n; |
| struct { |
| apr_time_t t; |
| pid_t p; |
| unsigned long i; |
| apr_uint32_t u; |
| } _ssl_seed; |
| if (counter == 0) { |
| apr_generate_random_bytes(stackdata, 256); |
| RAND_seed(stackdata, 128); |
| } |
| _ssl_seed.t = apr_time_now(); |
| _ssl_seed.p = getpid(); |
| _ssl_seed.i = ssl_thread_id(); |
| apr_atomic_inc32(&counter); |
| _ssl_seed.u = counter; |
| RAND_seed((unsigned char *)&_ssl_seed, sizeof(_ssl_seed)); |
| /* |
| * seed in some current state of the run-time stack (128 bytes) |
| */ |
| n = ssl_rand_choosenum(0, sizeof(stackdata)-128-1); |
| RAND_seed(stackdata + n, 128); |
| } |
| return RAND_status(); |
| } |
| |
| static int ssl_rand_make(const char *file, int len, int base64) |
| { |
| int r; |
| int num = len; |
| BIO *out = NULL; |
| |
| out = BIO_new(BIO_s_file()); |
| if (out == NULL) |
| return 0; |
| if ((r = BIO_write_filename(out, (char *)file)) < 0) { |
| BIO_free_all(out); |
| return 0; |
| } |
| if (base64) { |
| BIO *b64 = BIO_new(BIO_f_base64()); |
| if (b64 == NULL) { |
| BIO_free_all(out); |
| return 0; |
| } |
| out = BIO_push(b64, out); |
| } |
| while (num > 0) { |
| unsigned char buf[4096]; |
| int len = num; |
| if (len > sizeof(buf)) |
| len = sizeof(buf); |
| r = RAND_bytes(buf, len); |
| if (r <= 0) { |
| BIO_free_all(out); |
| return 0; |
| } |
| BIO_write(out, buf, len); |
| num -= len; |
| } |
| BIO_flush(out); |
| BIO_free_all(out); |
| return 1; |
| } |
| |
| TCN_IMPLEMENT_CALL(jint, SSL, initialize)(TCN_STDARGS, jstring engine) |
| { |
| int r = 0; |
| TCN_ALLOC_CSTRING(engine); |
| |
| UNREFERENCED(o); |
| if (!tcn_global_pool) { |
| TCN_FREE_CSTRING(engine); |
| return (jint)APR_EINVAL; |
| } |
| /* Check if already initialized */ |
| if (ssl_initialized++) { |
| TCN_FREE_CSTRING(engine); |
| return (jint)APR_SUCCESS; |
| } |
| if (SSLeay() < 0x0090700L) { |
| TCN_FREE_CSTRING(engine); |
| return (jint)APR_EINVAL; |
| } |
| /* We must register the library in full, to ensure our configuration |
| * code can successfully test the SSL environment. |
| */ |
| CRYPTO_malloc_init(); |
| ERR_load_crypto_strings(); |
| SSL_load_error_strings(); |
| SSL_library_init(); |
| #if HAVE_ENGINE_LOAD_BUILTIN_ENGINES |
| ENGINE_load_builtin_engines(); |
| #endif |
| #if OPENSSL_VERSION_NUMBER >= 0x00907001 |
| OPENSSL_load_builtin_modules(); |
| #endif |
| |
| #ifndef OPENSSL_NO_ENGINE |
| if (J2S(engine)) { |
| ENGINE *ee = NULL; |
| apr_status_t err = APR_SUCCESS; |
| if(strcmp(J2S(engine), "auto") == 0) { |
| ENGINE_register_all_complete(); |
| } |
| else { |
| if ((ee = ENGINE_by_id(J2S(engine))) == NULL |
| && (ee = ssl_try_load_engine(J2S(engine))) == NULL) |
| err = APR_ENOTIMPL; |
| else { |
| if (strcmp(J2S(engine), "chil") == 0) |
| ENGINE_ctrl(ee, ENGINE_CTRL_CHIL_SET_FORKCHECK, 1, 0, 0); |
| if (!ENGINE_set_default(ee, ENGINE_METHOD_ALL)) |
| err = APR_ENOTIMPL; |
| } |
| /* Free our "structural" reference. */ |
| if (ee) |
| ENGINE_free(ee); |
| } |
| if (err != APR_SUCCESS) { |
| TCN_FREE_CSTRING(engine); |
| ssl_init_cleanup(NULL); |
| return (jint)err; |
| } |
| tcn_ssl_engine = ee; |
| } |
| #endif |
| |
| memset(&tcn_password_callback, 0, sizeof(tcn_pass_cb_t)); |
| /* Initialize PRNG |
| * This will in most cases call the builtin |
| * low entropy seed. |
| */ |
| SSL_rand_seed(NULL); |
| /* For SSL_get_app_data2() at request time */ |
| SSL_init_app_data2_idx(); |
| |
| SSL_TMP_KEYS_INIT(r); |
| if (r) { |
| TCN_FREE_CSTRING(engine); |
| ssl_init_cleanup(NULL); |
| return APR_ENOTIMPL; |
| } |
| /* |
| * Let us cleanup the ssl library when the library is unloaded |
| */ |
| apr_pool_cleanup_register(tcn_global_pool, NULL, |
| ssl_init_cleanup, |
| apr_pool_cleanup_null); |
| /* Initialize thread support */ |
| ssl_thread_setup(tcn_global_pool); |
| TCN_FREE_CSTRING(engine); |
| return (jint)APR_SUCCESS; |
| } |
| |
| TCN_IMPLEMENT_CALL(jboolean, SSL, randLoad)(TCN_STDARGS, jstring file) |
| { |
| TCN_ALLOC_CSTRING(file); |
| int r; |
| UNREFERENCED(o); |
| r = SSL_rand_seed(J2S(file)); |
| TCN_FREE_CSTRING(file); |
| return r ? JNI_TRUE : JNI_FALSE; |
| } |
| |
| TCN_IMPLEMENT_CALL(jboolean, SSL, randSave)(TCN_STDARGS, jstring file) |
| { |
| TCN_ALLOC_CSTRING(file); |
| int r; |
| UNREFERENCED(o); |
| r = ssl_rand_save_file(J2S(file)); |
| TCN_FREE_CSTRING(file); |
| return r ? JNI_TRUE : JNI_FALSE; |
| } |
| |
| TCN_IMPLEMENT_CALL(jboolean, SSL, randMake)(TCN_STDARGS, jstring file, |
| jint length, jboolean base64) |
| { |
| TCN_ALLOC_CSTRING(file); |
| int r; |
| UNREFERENCED(o); |
| r = ssl_rand_make(J2S(file), length, base64); |
| TCN_FREE_CSTRING(file); |
| return r ? JNI_TRUE : JNI_FALSE; |
| } |
| |
| /* OpenSSL Java Stream BIO */ |
| |
| typedef struct { |
| int refcount; |
| apr_pool_t *pool; |
| tcn_callback_t cb; |
| } BIO_JAVA; |
| |
| |
| static apr_status_t generic_bio_cleanup(void *data) |
| { |
| BIO *b = (BIO *)data; |
| |
| if (b) { |
| BIO_free(b); |
| } |
| return APR_SUCCESS; |
| } |
| |
| void SSL_BIO_close(BIO *bi) |
| { |
| if (bi == NULL) |
| return; |
| if (bi->ptr != NULL && (bi->flags & SSL_BIO_FLAG_CALLBACK)) { |
| BIO_JAVA *j = (BIO_JAVA *)bi->ptr; |
| j->refcount--; |
| if (j->refcount == 0) { |
| if (j->pool) |
| apr_pool_cleanup_run(j->pool, bi, generic_bio_cleanup); |
| else |
| BIO_free(bi); |
| } |
| } |
| else |
| BIO_free(bi); |
| } |
| |
| void SSL_BIO_doref(BIO *bi) |
| { |
| if (bi == NULL) |
| return; |
| if (bi->ptr != NULL && (bi->flags & SSL_BIO_FLAG_CALLBACK)) { |
| BIO_JAVA *j = (BIO_JAVA *)bi->ptr; |
| j->refcount++; |
| } |
| } |
| |
| |
| static int jbs_new(BIO *bi) |
| { |
| BIO_JAVA *j; |
| |
| if ((j = OPENSSL_malloc(sizeof(BIO_JAVA))) == NULL) |
| return 0; |
| j->pool = NULL; |
| j->refcount = 1; |
| bi->shutdown = 1; |
| bi->init = 0; |
| bi->num = -1; |
| bi->ptr = (char *)j; |
| |
| return 1; |
| } |
| |
| static int jbs_free(BIO *bi) |
| { |
| if (bi == NULL) |
| return 0; |
| if (bi->ptr != NULL) { |
| BIO_JAVA *j = (BIO_JAVA *)bi->ptr; |
| if (bi->init) { |
| bi->init = 0; |
| TCN_UNLOAD_CLASS(j->cb.env, j->cb.obj); |
| } |
| OPENSSL_free(bi->ptr); |
| } |
| bi->ptr = NULL; |
| return 1; |
| } |
| |
| static int jbs_write(BIO *b, const char *in, int inl) |
| { |
| jint ret = 0; |
| if (b->init && in != NULL) { |
| BIO_JAVA *j = (BIO_JAVA *)b->ptr; |
| JNIEnv *e = j->cb.env; |
| jbyteArray jb = (*e)->NewByteArray(e, inl); |
| if (!(*e)->ExceptionOccurred(e)) { |
| (*e)->SetByteArrayRegion(e, jb, 0, inl, (jbyte *)in); |
| ret = (*e)->CallIntMethod(e, j->cb.obj, |
| j->cb.mid[0], jb); |
| (*e)->ReleaseByteArrayElements(e, jb, (jbyte *)in, JNI_ABORT); |
| (*e)->DeleteLocalRef(e, jb); |
| } |
| } |
| return ret; |
| } |
| |
| static int jbs_read(BIO *b, char *out, int outl) |
| { |
| jint ret = 0; |
| if (b->init && out != NULL) { |
| BIO_JAVA *j = (BIO_JAVA *)b->ptr; |
| JNIEnv *e = j->cb.env; |
| jbyteArray jb = (*e)->NewByteArray(e, outl); |
| if (!(*e)->ExceptionOccurred(e)) { |
| ret = (*e)->CallIntMethod(e, j->cb.obj, |
| j->cb.mid[1], jb); |
| if (ret > 0) { |
| jbyte *jout = (*e)->GetPrimitiveArrayCritical(e, jb, NULL); |
| memcpy(out, jout, ret); |
| (*e)->ReleasePrimitiveArrayCritical(e, jb, jout, 0); |
| } |
| (*e)->DeleteLocalRef(e, jb); |
| } |
| } |
| return ret; |
| } |
| |
| static int jbs_puts(BIO *b, const char *in) |
| { |
| int ret = 0; |
| if (b->init && in != NULL) { |
| BIO_JAVA *j = (BIO_JAVA *)b->ptr; |
| JNIEnv *e = j->cb.env; |
| ret = (*e)->CallIntMethod(e, j->cb.obj, |
| j->cb.mid[2], |
| tcn_new_string(e, in)); |
| } |
| return ret; |
| } |
| |
| static int jbs_gets(BIO *b, char *out, int outl) |
| { |
| int ret = 0; |
| if (b->init && out != NULL) { |
| BIO_JAVA *j = (BIO_JAVA *)b->ptr; |
| JNIEnv *e = j->cb.env; |
| jobject o; |
| if ((o = (*e)->CallObjectMethod(e, j->cb.obj, |
| j->cb.mid[3], (jint)(outl - 1)))) { |
| TCN_ALLOC_CSTRING(o); |
| if (J2S(o)) { |
| int l = (int)strlen(J2S(o)); |
| if (l < outl) { |
| strcpy(out, J2S(o)); |
| ret = outl; |
| } |
| } |
| TCN_FREE_CSTRING(o); |
| } |
| } |
| return ret; |
| } |
| |
| static long jbs_ctrl(BIO *b, int cmd, long num, void *ptr) |
| { |
| return 0; |
| } |
| |
| static BIO_METHOD jbs_methods = { |
| BIO_TYPE_FILE, |
| "Java Callback", |
| jbs_write, |
| jbs_read, |
| jbs_puts, |
| jbs_gets, |
| jbs_ctrl, |
| jbs_new, |
| jbs_free, |
| NULL |
| }; |
| |
| static BIO_METHOD *BIO_jbs() |
| { |
| return(&jbs_methods); |
| } |
| |
| TCN_IMPLEMENT_CALL(jlong, SSL, newBIO)(TCN_STDARGS, jlong pool, |
| jobject callback) |
| { |
| BIO *bio = NULL; |
| BIO_JAVA *j; |
| jclass cls; |
| |
| UNREFERENCED(o); |
| |
| if ((bio = BIO_new(BIO_jbs())) == NULL) { |
| tcn_ThrowException(e, "Create BIO failed"); |
| goto init_failed; |
| } |
| j = (BIO_JAVA *)bio->ptr; |
| if ((j = (BIO_JAVA *)bio->ptr) == NULL) { |
| tcn_ThrowException(e, "Create BIO failed"); |
| goto init_failed; |
| } |
| j->pool = J2P(pool, apr_pool_t *); |
| if (j->pool) { |
| apr_pool_cleanup_register(j->pool, (const void *)bio, |
| generic_bio_cleanup, |
| apr_pool_cleanup_null); |
| } |
| |
| cls = (*e)->GetObjectClass(e, callback); |
| j->cb.env = e; |
| j->cb.mid[0] = (*e)->GetMethodID(e, cls, "write", "([B)I"); |
| j->cb.mid[1] = (*e)->GetMethodID(e, cls, "read", "([B)I"); |
| j->cb.mid[2] = (*e)->GetMethodID(e, cls, "puts", "(Ljava/lang/String;)I"); |
| j->cb.mid[3] = (*e)->GetMethodID(e, cls, "gets", "(I)Ljava/lang/String;"); |
| /* TODO: Check if method id's are valid */ |
| j->cb.obj = (*e)->NewGlobalRef(e, callback); |
| |
| bio->init = 1; |
| bio->flags = SSL_BIO_FLAG_CALLBACK; |
| return P2J(bio); |
| init_failed: |
| return 0; |
| } |
| |
| TCN_IMPLEMENT_CALL(jint, SSL, closeBIO)(TCN_STDARGS, jlong bio) |
| { |
| BIO *b = J2P(bio, BIO *); |
| UNREFERENCED_STDARGS; |
| SSL_BIO_close(b); |
| return APR_SUCCESS; |
| } |
| |
| TCN_IMPLEMENT_CALL(void, SSL, setPasswordCallback)(TCN_STDARGS, |
| jobject callback) |
| { |
| jclass cls; |
| |
| UNREFERENCED(o); |
| if (tcn_password_callback.cb.obj) { |
| TCN_UNLOAD_CLASS(tcn_password_callback.cb.env, |
| tcn_password_callback.cb.obj); |
| } |
| cls = (*e)->GetObjectClass(e, callback); |
| tcn_password_callback.cb.env = e; |
| tcn_password_callback.cb.mid[0] = (*e)->GetMethodID(e, cls, "callback", |
| "(Ljava/lang/String;)Ljava/lang/String;"); |
| /* TODO: Check if method id is valid */ |
| tcn_password_callback.cb.obj = (*e)->NewGlobalRef(e, callback); |
| |
| } |
| |
| TCN_IMPLEMENT_CALL(void, SSL, setPassword)(TCN_STDARGS, jstring password) |
| { |
| TCN_ALLOC_CSTRING(password); |
| UNREFERENCED(o); |
| if (J2S(password)) { |
| strncpy(tcn_password_callback.password, J2S(password), SSL_MAX_PASSWORD_LEN); |
| tcn_password_callback.password[SSL_MAX_PASSWORD_LEN-1] = '\0'; |
| } |
| TCN_FREE_CSTRING(password); |
| } |
| |
| TCN_IMPLEMENT_CALL(jboolean, SSL, generateRSATempKey)(TCN_STDARGS, jint idx) |
| { |
| int r = 1; |
| UNREFERENCED_STDARGS; |
| SSL_TMP_KEY_FREE(RSA, idx); |
| switch (idx) { |
| case SSL_TMP_KEY_RSA_512: |
| r = SSL_TMP_KEY_INIT_RSA(512); |
| break; |
| case SSL_TMP_KEY_RSA_1024: |
| r = SSL_TMP_KEY_INIT_RSA(1024); |
| break; |
| case SSL_TMP_KEY_RSA_2048: |
| r = SSL_TMP_KEY_INIT_RSA(2048); |
| break; |
| case SSL_TMP_KEY_RSA_4096: |
| r = SSL_TMP_KEY_INIT_RSA(4096); |
| break; |
| } |
| return r ? JNI_FALSE : JNI_TRUE; |
| } |
| |
| TCN_IMPLEMENT_CALL(jboolean, SSL, loadDSATempKey)(TCN_STDARGS, jint idx, |
| jstring file) |
| { |
| jboolean r = JNI_FALSE; |
| TCN_ALLOC_CSTRING(file); |
| DH *dh; |
| UNREFERENCED(o); |
| |
| if (!J2S(file)) |
| return JNI_FALSE; |
| SSL_TMP_KEY_FREE(DSA, idx); |
| if ((dh = SSL_dh_get_param_from_file(J2S(file)))) { |
| SSL_temp_keys[idx] = dh; |
| r = JNI_TRUE; |
| } |
| TCN_FREE_CSTRING(file); |
| return r; |
| } |
| |
| TCN_IMPLEMENT_CALL(jstring, SSL, getLastError)(TCN_STDARGS) |
| { |
| char buf[256]; |
| UNREFERENCED(o); |
| ERR_error_string(ERR_get_error(), buf); |
| return tcn_new_string(e, buf); |
| } |
| |
| #else |
| /* OpenSSL is not supported |
| * If someday we make OpenSSL optional |
| * APR_ENOTIMPL will go here |
| */ |
| #error "No OpenSSL Toolkit defined." |
| #endif |