| Index: c/ssl.c
|
| diff --git a/c/ssl.c b/c/ssl.c
|
| index f8302d43a46e733a518d1fde35133b5d39a3cc6e..15891508348ad9d21b64db0416b4dd948d443fb9 100644
|
| --- a/c/ssl.c
|
| +++ b/c/ssl.c
|
| @@ -1,3 +1,18 @@
|
| +/*
|
| + * Copyright 2016 The Netty Project
|
| + *
|
| + * The Netty Project licenses this file to you 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.
|
| + */
|
| /* Licensed to the Apache Software Foundation (ASF) under one or more
|
| * contributor license agreements. See the NOTICE file distributed with
|
| * this work for additional information regarding copyright ownership.
|
| @@ -14,34 +29,25 @@
|
| * limitations under the License.
|
| */
|
|
|
| -/*
|
| - *
|
| - * @author Mladen Turk
|
| - * @version $Id: ssl.c 1649733 2015-01-06 04:42:24Z billbarker $
|
| - */
|
| -
|
| +#include <stdbool.h>
|
| +#include <openssl/bio.h>
|
| #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 "apr_strings.h"
|
| +#include "apr_portable.h"
|
| #include "ssl_private.h"
|
|
|
| static int ssl_initialized = 0;
|
| -static char *ssl_global_rand_file = NULL;
|
| 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;
|
|
|
| /* Global reference to the pool used by the dynamic mutexes */
|
| static apr_pool_t *dynlockpool = NULL;
|
|
|
| -static jclass byteArrayClass;
|
| -static jclass stringClass;
|
| -
|
| /* Dynamic lock structure */
|
| struct CRYPTO_dynlock_value {
|
| apr_pool_t *pool;
|
| @@ -50,6 +56,16 @@ struct CRYPTO_dynlock_value {
|
| apr_thread_mutex_t *mutex;
|
| };
|
|
|
| +struct TCN_bio_bytebuffer {
|
| + // Pointer arithmetic is done on this variable. The type must correspond to a "byte" size.
|
| + char* buffer;
|
| + char* nonApplicationBuffer;
|
| + jint nonApplicationBufferSize;
|
| + jint nonApplicationBufferOffset;
|
| + jint nonApplicationBufferLength;
|
| + jint bufferLength;
|
| + bool bufferIsSSLWriteSink;
|
| +};
|
|
|
| /*
|
| * Handle the Temporary RSA Keys and DH Params
|
| @@ -67,17 +83,10 @@ struct CRYPTO_dynlock_value {
|
| 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); \
|
| @@ -120,10 +129,6 @@ static const jint supported_ssl_opts = 0
|
| | SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
|
| #endif
|
|
|
| -#ifdef SSL_OP_EPHEMERAL_RSA
|
| - | SSL_OP_EPHEMERAL_RSA
|
| -#endif
|
| -
|
| #ifdef SSL_OP_LEGACY_SERVER_CONNECT
|
| | SSL_OP_LEGACY_SERVER_CONNECT
|
| #endif
|
| @@ -229,66 +234,311 @@ static const jint supported_ssl_opts = 0
|
| #endif
|
| | 0;
|
|
|
| -static int ssl_tmp_key_init_rsa(int bits, int idx)
|
| -{
|
| -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
|
| - return 0;
|
| -#else
|
| +static jint tcn_flush_sslbuffer_to_bytebuffer(struct TCN_bio_bytebuffer* bioUserData) {
|
| + jint writeAmount = TCN_MIN(bioUserData->bufferLength, bioUserData->nonApplicationBufferLength) * sizeof(char);
|
| + jint writeChunk = bioUserData->nonApplicationBufferSize - bioUserData->nonApplicationBufferOffset;
|
|
|
| -#ifdef OPENSSL_FIPS
|
| - /**
|
| - * Short RSA keys cannot be generated in FIPS mode.
|
| - */
|
| - if (bits < 1024)
|
| +#ifdef NETTY_TCNATIVE_BIO_DEBUG
|
| + fprintf(stderr, "tcn_flush_sslbuffer_to_bytebuffer1 bioUserData->nonApplicationBufferLength %d bioUserData->nonApplicationBufferOffset %d writeChunk %d writeAmount %d\n", bioUserData->nonApplicationBufferLength, bioUserData->nonApplicationBufferOffset, writeChunk, writeAmount);
|
| +#endif
|
| +
|
| + // check if we need to account for wrap around when draining the internal SSL buffer.
|
| + if (writeAmount > writeChunk) {
|
| + jint newnonApplicationBufferOffset = writeAmount - writeChunk;
|
| + memcpy(bioUserData->buffer, &bioUserData->nonApplicationBuffer[bioUserData->nonApplicationBufferOffset], (size_t) writeChunk);
|
| + memcpy(&bioUserData->buffer[writeChunk], bioUserData->nonApplicationBuffer, (size_t) newnonApplicationBufferOffset);
|
| + bioUserData->nonApplicationBufferOffset = newnonApplicationBufferOffset;
|
| + } else {
|
| + memcpy(bioUserData->buffer, &bioUserData->nonApplicationBuffer[bioUserData->nonApplicationBufferOffset], (size_t) writeAmount);
|
| + bioUserData->nonApplicationBufferOffset += writeAmount;
|
| + }
|
| + bioUserData->nonApplicationBufferLength -= writeAmount;
|
| + bioUserData->bufferLength -= writeAmount;
|
| + bioUserData->buffer += writeAmount; // Pointer arithmetic based on char* type
|
| +
|
| + if (bioUserData->nonApplicationBufferLength == 0) {
|
| + bioUserData->nonApplicationBufferOffset = 0;
|
| + }
|
| +
|
| +#ifdef NETTY_TCNATIVE_BIO_DEBUG
|
| + fprintf(stderr, "tcn_flush_sslbuffer_to_bytebuffer2 bioUserData->nonApplicationBufferLength %d bioUserData->nonApplicationBufferOffset %d\n", bioUserData->nonApplicationBufferLength, bioUserData->nonApplicationBufferOffset);
|
| +#endif
|
| +
|
| + return writeAmount;
|
| +}
|
| +
|
| +static jint tcn_write_to_bytebuffer(BIO* bio, const char* in, int inl) {
|
| + jint writeAmount = 0;
|
| + jint writeChunk;
|
| + struct TCN_bio_bytebuffer* bioUserData = (struct TCN_bio_bytebuffer*) BIO_get_data(bio);
|
| + TCN_ASSERT(bioUserData != NULL);
|
| +
|
| +#ifdef NETTY_TCNATIVE_BIO_DEBUG
|
| + fprintf(stderr, "tcn_write_to_bytebuffer bioUserData->bufferIsSSLWriteSink %d inl %d [%.*s]\n", bioUserData->bufferIsSSLWriteSink, inl, inl, in);
|
| +#endif
|
| +
|
| + if (in == NULL || inl <= 0) {
|
| + return 0;
|
| + }
|
| +
|
| + // If the buffer is currently being used for reading then we have to use the internal SSL buffer to queue the data.
|
| + if (!bioUserData->bufferIsSSLWriteSink) {
|
| + jint nonApplicationBufferFreeSpace = bioUserData->nonApplicationBufferSize - bioUserData->nonApplicationBufferLength;
|
| + jint startIndex;
|
| +
|
| +#ifdef NETTY_TCNATIVE_BIO_DEBUG
|
| + fprintf(stderr, "tcn_write_to_bytebuffer nonApplicationBufferFreeSpace %d\n", nonApplicationBufferFreeSpace);
|
| +#endif
|
| + if (nonApplicationBufferFreeSpace == 0) {
|
| + BIO_set_retry_write(bio); /* buffer is full */
|
| + return -1;
|
| + }
|
| +
|
| + writeAmount = TCN_MIN(nonApplicationBufferFreeSpace, (jint) inl) * sizeof(char);
|
| + startIndex = bioUserData->nonApplicationBufferOffset + bioUserData->nonApplicationBufferLength;
|
| + writeChunk = bioUserData->nonApplicationBufferSize - startIndex;
|
| +
|
| +#ifdef NETTY_TCNATIVE_BIO_DEBUG
|
| + fprintf(stderr, "tcn_write_to_bytebuffer bioUserData->nonApplicationBufferLength %d bioUserData->nonApplicationBufferOffset %d startIndex %d writeChunk %d writeAmount %d\n", bioUserData->nonApplicationBufferLength, bioUserData->nonApplicationBufferOffset, startIndex, writeChunk, writeAmount);
|
| +#endif
|
| +
|
| + // check if the write will wrap around the buffer.
|
| + if (writeAmount > writeChunk) {
|
| + memcpy(&bioUserData->nonApplicationBuffer[startIndex], in, (size_t) writeChunk);
|
| + memcpy(bioUserData->nonApplicationBuffer, &in[writeChunk], (size_t) (writeAmount - writeChunk));
|
| + } else {
|
| + memcpy(&bioUserData->nonApplicationBuffer[startIndex], in, (size_t) writeAmount);
|
| + }
|
| + bioUserData->nonApplicationBufferLength += writeAmount;
|
| + // This write amount will not be used by Java, and doesn't correlate to the ByteBuffer source.
|
| + // The internal SSL buffer exists because a SSL_read operation may actually write data (e.g. handshake).
|
| + return writeAmount;
|
| + }
|
| +
|
| + if (bioUserData->buffer == NULL || bioUserData->bufferLength == 0) {
|
| + BIO_set_retry_write(bio); /* no buffer to write into */
|
| + return -1;
|
| + }
|
| +
|
| + // First check if we need to drain data queued in the internal SSL buffer.
|
| + if (bioUserData->nonApplicationBufferLength != 0) {
|
| + writeAmount = tcn_flush_sslbuffer_to_bytebuffer(bioUserData);
|
| + }
|
| +
|
| + // Next write "in" into what ever space the ByteBuffer has available.
|
| + writeChunk = TCN_MIN(bioUserData->bufferLength, (jint) inl) * sizeof(char);
|
| +
|
| +#ifdef NETTY_TCNATIVE_BIO_DEBUG
|
| + fprintf(stderr, "tcn_write_to_bytebuffer2 writeChunk %d\n", writeChunk);
|
| +#endif
|
| +
|
| + memcpy(bioUserData->buffer, in, (size_t) writeChunk);
|
| + bioUserData->bufferLength -= writeChunk;
|
| + bioUserData->buffer += writeChunk; // Pointer arithmetic based on char* type
|
| +
|
| + return writeAmount + writeChunk;
|
| +}
|
| +
|
| +static jint tcn_read_from_bytebuffer(BIO* bio, char *out, int outl) {
|
| + jint readAmount;
|
| + struct TCN_bio_bytebuffer* bioUserData = (struct TCN_bio_bytebuffer*) BIO_get_data(bio);
|
| + TCN_ASSERT(bioUserData != NULL);
|
| +
|
| +#ifdef NETTY_TCNATIVE_BIO_DEBUG
|
| + fprintf(stderr, "tcn_read_from_bytebuffer bioUserData->bufferIsSSLWriteSink %d outl %d [%.*s]\n", bioUserData->bufferIsSSLWriteSink, outl, outl, out);
|
| +#endif
|
| +
|
| + if (out == NULL || outl <= 0) {
|
| return 0;
|
| + }
|
| +
|
| + if (bioUserData->bufferIsSSLWriteSink || bioUserData->buffer == NULL || bioUserData->bufferLength == 0) {
|
| + // During handshake this may happen, and it means we are not setup to read yet.
|
| + BIO_set_retry_read(bio);
|
| + return -1;
|
| + }
|
| +
|
| + readAmount = TCN_MIN(bioUserData->bufferLength, (jint) outl) * sizeof(char);
|
| +
|
| +#ifdef NETTY_TCNATIVE_BIO_DEBUG
|
| + fprintf(stderr, "tcn_read_from_bytebuffer readAmount %d\n", readAmount);
|
| #endif
|
|
|
| - BIGNUM *e = BN_new();
|
| - RSA *rsa = RSA_new();
|
| - int ret = 1;
|
| + memcpy(out, bioUserData->buffer, (size_t) readAmount);
|
| + bioUserData->bufferLength -= readAmount;
|
| + bioUserData->buffer += readAmount; // Pointer arithmetic based on char* type
|
|
|
| - if (e == NULL ||
|
| - rsa == NULL ||
|
| - !BN_set_word(e, RSA_F4) ||
|
| - RSA_generate_key_ex(rsa, bits, e, NULL) != 1) {
|
| - goto err;
|
| + return readAmount;
|
| +}
|
| +
|
| +static int bio_java_bytebuffer_create(BIO* bio) {
|
| + struct TCN_bio_bytebuffer* bioUserData = (struct TCN_bio_bytebuffer*) OPENSSL_malloc(sizeof(struct TCN_bio_bytebuffer));
|
| + if (bioUserData == NULL) {
|
| + return 0;
|
| }
|
| + // The actual ByteBuffer is set from java and may be swapped out for each operation.
|
| + bioUserData->buffer = NULL;
|
| + bioUserData->bufferLength = 0;
|
| + bioUserData->bufferIsSSLWriteSink = false;
|
| + bioUserData->nonApplicationBuffer = NULL;
|
| + bioUserData->nonApplicationBufferSize = 0;
|
| + bioUserData->nonApplicationBufferOffset = 0;
|
| + bioUserData->nonApplicationBufferLength = 0;
|
|
|
| - SSL_temp_keys[idx] = rsa;
|
| - rsa = NULL;
|
| - ret = 0;
|
| + BIO_set_data(bio, bioUserData);
|
|
|
| -err:
|
| - BN_free(e);
|
| - RSA_free(rsa);
|
| - return ret;
|
| -#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
|
| + // In order to for OpenSSL to properly manage the lifetime of a BIO it relies on some shutdown and init state.
|
| + // The behavior expected by OpenSSL can be found here: https://www.openssl.org/docs/man1.1.0/crypto/BIO_set_data.html
|
| + BIO_set_shutdown(bio, 1);
|
| + BIO_set_init(bio, 1);
|
| +
|
| + return 1;
|
| }
|
|
|
| -static int ssl_tmp_key_init_dh(int bits, int idx)
|
| -{
|
| -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(OPENSSL_USE_DEPRECATED)
|
| - if (!(SSL_temp_keys[idx] =
|
| - SSL_dh_get_tmp_param(bits)))
|
| +static int bio_java_bytebuffer_destroy(BIO* bio) {
|
| + struct TCN_bio_bytebuffer* bioUserData;
|
| +
|
| + if (bio == NULL) {
|
| + return 0;
|
| + }
|
| +
|
| + bioUserData = (struct TCN_bio_bytebuffer*) BIO_get_data(bio);
|
| + if (bioUserData == NULL) {
|
| return 1;
|
| - else
|
| + }
|
| +
|
| + if (bioUserData->nonApplicationBuffer != NULL) {
|
| + OPENSSL_free(bioUserData->nonApplicationBuffer);
|
| + bioUserData->nonApplicationBuffer = NULL;
|
| + }
|
| +
|
| + // The buffer is not owned by tcn, so just free the native memory.
|
| + OPENSSL_free(bioUserData);
|
| + BIO_set_data(bio, NULL);
|
| +
|
| + return 1;
|
| +}
|
| +
|
| +static int bio_java_bytebuffer_write(BIO* bio, const char* in, int inl) {
|
| + BIO_clear_retry_flags(bio);
|
| + return (int) tcn_write_to_bytebuffer(bio, in, inl);
|
| +}
|
| +
|
| +static int bio_java_bytebuffer_read(BIO* bio, char* out, int outl) {
|
| + BIO_clear_retry_flags(bio);
|
| + return (int) tcn_read_from_bytebuffer(bio, out, outl);
|
| +}
|
| +
|
| +static int bio_java_bytebuffer_puts(BIO* bio, const char *in) {
|
| + BIO_clear_retry_flags(bio);
|
| + return (int) tcn_write_to_bytebuffer(bio, in, strlen(in));
|
| +}
|
| +
|
| +static int bio_java_bytebuffer_gets(BIO* b, char* out, int outl) {
|
| + // Not supported https://www.openssl.org/docs/man1.0.2/crypto/BIO_write.html
|
| + return -2;
|
| +}
|
| +
|
| +static long bio_java_bytebuffer_ctrl(BIO* bio, int cmd, long num, void* ptr) {
|
| + // see https://www.openssl.org/docs/man1.0.1/crypto/BIO_ctrl.html
|
| + switch (cmd) {
|
| + case BIO_CTRL_GET_CLOSE:
|
| + return (long) BIO_get_shutdown(bio);
|
| + case BIO_CTRL_SET_CLOSE:
|
| + BIO_set_shutdown(bio, (int) num);
|
| + return 1;
|
| + case BIO_CTRL_FLUSH:
|
| + return 1;
|
| + default:
|
| + return 0;
|
| + }
|
| +}
|
| +
|
| +TCN_IMPLEMENT_CALL(jint, SSL, bioLengthByteBuffer)(TCN_STDARGS, jlong bioAddress) {
|
| + BIO* bio = J2P(bioAddress, BIO*);
|
| + struct TCN_bio_bytebuffer* bioUserData;
|
| +
|
| + if (bio == NULL) {
|
| + tcn_ThrowException(e, "bio is null");
|
| + return 0;
|
| + }
|
| +
|
| + bioUserData = (struct TCN_bio_bytebuffer*) BIO_get_data(bio);
|
| + return bioUserData == NULL ? 0 : bioUserData->bufferLength;
|
| +}
|
| +
|
| +TCN_IMPLEMENT_CALL(jint, SSL, bioLengthNonApplication)(TCN_STDARGS, jlong bioAddress) {
|
| + BIO* bio = J2P(bioAddress, BIO*);
|
| + struct TCN_bio_bytebuffer* bioUserData;
|
| +
|
| + if (bio == NULL) {
|
| + tcn_ThrowException(e, "bio is null");
|
| return 0;
|
| + }
|
| +
|
| + bioUserData = (struct TCN_bio_bytebuffer*) BIO_get_data(bio);
|
| + return bioUserData == NULL ? 0 : bioUserData->nonApplicationBufferLength;
|
| +}
|
| +
|
| +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
| +static BIO_METHOD bio_java_bytebuffer_methods = {
|
| + BIO_TYPE_MEM,
|
| + "Java ByteBuffer",
|
| + bio_java_bytebuffer_write,
|
| + bio_java_bytebuffer_read,
|
| + bio_java_bytebuffer_puts,
|
| + bio_java_bytebuffer_gets,
|
| + bio_java_bytebuffer_ctrl,
|
| + bio_java_bytebuffer_create,
|
| + bio_java_bytebuffer_destroy,
|
| + NULL
|
| +};
|
| #else
|
| - return 0;
|
| +static BIO_METHOD* bio_java_bytebuffer_methods = NULL;
|
| +
|
| +static void init_bio_methods(void) {
|
| + bio_java_bytebuffer_methods = BIO_meth_new(BIO_TYPE_MEM, "Java ByteBuffer");
|
| + BIO_meth_set_write(bio_java_bytebuffer_methods, &bio_java_bytebuffer_write);
|
| + BIO_meth_set_read(bio_java_bytebuffer_methods, &bio_java_bytebuffer_read);
|
| + BIO_meth_set_puts(bio_java_bytebuffer_methods, &bio_java_bytebuffer_puts);
|
| + BIO_meth_set_gets(bio_java_bytebuffer_methods, &bio_java_bytebuffer_gets);
|
| + BIO_meth_set_ctrl(bio_java_bytebuffer_methods, &bio_java_bytebuffer_ctrl);
|
| + BIO_meth_set_create(bio_java_bytebuffer_methods, &bio_java_bytebuffer_create);
|
| + BIO_meth_set_destroy(bio_java_bytebuffer_methods, &bio_java_bytebuffer_destroy);
|
| +}
|
| +
|
| +static void free_bio_methods(void) {
|
| + BIO_meth_free(bio_java_bytebuffer_methods);
|
| +}
|
| +#endif
|
| +
|
| +static BIO_METHOD* BIO_java_bytebuffer() {
|
| +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
| + return &bio_java_bytebuffer_methods;
|
| +#else
|
| + return bio_java_bytebuffer_methods;
|
| #endif
|
| }
|
|
|
| +static int ssl_tmp_key_init_dh(int bits, int idx)
|
| +{
|
| +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(OPENSSL_USE_DEPRECATED) || defined(LIBRESSL_VERSION_NUMBER)
|
| + return (SSL_temp_keys[idx] = SSL_dh_get_tmp_param(bits)) ? 0 : 1;
|
| +#else
|
| + return 0;
|
| +#endif
|
| +}
|
|
|
| TCN_IMPLEMENT_CALL(jint, SSL, version)(TCN_STDARGS)
|
| {
|
| UNREFERENCED_STDARGS;
|
| - return (jint) SSLeay();
|
| + return OpenSSL_version_num();
|
| }
|
|
|
| TCN_IMPLEMENT_CALL(jstring, SSL, versionString)(TCN_STDARGS)
|
| {
|
| UNREFERENCED(o);
|
| - return AJP_TO_JSTRING(SSLeay_version(SSLEAY_VERSION));
|
| + return AJP_TO_JSTRING(OpenSSL_version(OPENSSL_VERSION));
|
| }
|
|
|
| /*
|
| @@ -302,14 +552,6 @@ static apr_status_t ssl_init_cleanup(void *data)
|
| return APR_SUCCESS;
|
| ssl_initialized = 0;
|
|
|
| - if (tcn_password_callback.cb.obj) {
|
| - JNIEnv *env;
|
| - tcn_get_java_env(&env);
|
| - TCN_UNLOAD_CLASS(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.
|
| @@ -329,7 +571,12 @@ static apr_status_t ssl_init_cleanup(void *data)
|
| #if OPENSSL_VERSION_NUMBER >= 0x00907001
|
| CRYPTO_cleanup_all_ex_data();
|
| #endif
|
| - ERR_remove_state(0);
|
| +#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
| + ERR_remove_thread_state(NULL);
|
| +#endif
|
| +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
| + free_bio_methods();
|
| +#endif
|
|
|
| /* Don't call ERR_free_strings here; ERR_load_*_strings only
|
| * actually load the error strings once per process due to static
|
| @@ -401,11 +648,16 @@ static unsigned long ssl_thread_id(void)
|
| #endif
|
| }
|
|
|
| +static void ssl_set_thread_id(CRYPTO_THREADID *id)
|
| +{
|
| + CRYPTO_THREADID_set_numeric(id, ssl_thread_id());
|
| +}
|
| +
|
| static apr_status_t ssl_thread_cleanup(void *data)
|
| {
|
| UNREFERENCED(data);
|
| CRYPTO_set_locking_callback(NULL);
|
| - CRYPTO_set_id_callback(NULL);
|
| + CRYPTO_THREADID_set_callback(NULL);
|
| CRYPTO_set_dynlock_create_callback(NULL);
|
| CRYPTO_set_dynlock_lock_callback(NULL);
|
| CRYPTO_set_dynlock_destroy_callback(NULL);
|
| @@ -466,8 +718,6 @@ static struct CRYPTO_dynlock_value *ssl_dyn_create_function(const char *file,
|
| static void ssl_dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l,
|
| const char *file, int line)
|
| {
|
| -
|
| -
|
| if (mode & CRYPTO_LOCK) {
|
| apr_thread_mutex_lock(l->mutex);
|
| }
|
| @@ -493,6 +743,7 @@ static void ssl_dyn_destroy_function(struct CRYPTO_dynlock_value *l,
|
| */
|
| apr_pool_destroy(l->pool);
|
| }
|
| +
|
| static void ssl_thread_setup(apr_pool_t *p)
|
| {
|
| int i;
|
| @@ -505,7 +756,7 @@ static void ssl_thread_setup(apr_pool_t *p)
|
| APR_THREAD_MUTEX_DEFAULT, p);
|
| }
|
|
|
| - CRYPTO_set_id_callback(ssl_thread_id);
|
| + CRYPTO_THREADID_set_callback(ssl_set_thread_id);
|
| CRYPTO_set_locking_callback(ssl_thread_lock);
|
|
|
| /* Set up dynamic locking scaffolding for OpenSSL to use at its
|
| @@ -520,113 +771,9 @@ static void ssl_thread_setup(apr_pool_t *p)
|
| 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)
|
| -{
|
| - int n;
|
| -
|
| - if (file == NULL)
|
| - file = ssl_global_rand_file;
|
| - if (file && (strcmp(file, "builtin") == 0))
|
| - return -1;
|
| -// BoringSsl doesn't support RAND_file_name, but RAND_status() returns 1 anyways
|
| -#ifndef OPENSSL_IS_BORINGSSL
|
| - if (file == NULL) {
|
| - char buffer[APR_PATH_MAX];
|
| - file = RAND_file_name(buffer, sizeof(buffer));
|
| - }
|
| -#endif
|
| - if (file) {
|
| -#ifdef HAVE_SSL_RAND_EGD
|
| - if (strncmp(file, "egd:", 4) == 0) {
|
| - if ((n = RAND_egd(file + 4)) > 0)
|
| - return n;
|
| - else
|
| - return -1;
|
| - }
|
| -#endif
|
| - if ((n = RAND_load_file(file, -1)) > 0)
|
| - return n;
|
| - }
|
| - 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)
|
| -{
|
| -#ifndef OPENSSL_IS_BORINGSSL
|
| - char buffer[APR_PATH_MAX];
|
| - int n;
|
| - if (file == NULL) {
|
| - file = RAND_file_name(buffer, sizeof(buffer));
|
| -#ifdef HAVE_SSL_RAND_EGD
|
| - } else if ((n = RAND_egd(file)) > 0) {
|
| - return 0;
|
| -#endif
|
| - }
|
| - if (file == NULL || !RAND_write_file(file))
|
| - return 0;
|
| - else
|
| - return 1;
|
| -#else
|
| - // BoringSsl doesn't have RAND_file_name/RAND_write_file and RAND_egd always return 255
|
| - return 0;
|
| -#endif
|
| -}
|
| -
|
| -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();
|
| -}
|
| -
|
| TCN_IMPLEMENT_CALL(jint, SSL, initialize)(TCN_STDARGS, jstring engine)
|
| {
|
| int r = 0;
|
| - jclass clazz;
|
| - jclass sClazz;
|
|
|
| TCN_ALLOC_CSTRING(engine);
|
|
|
| @@ -642,18 +789,20 @@ TCN_IMPLEMENT_CALL(jint, SSL, initialize)(TCN_STDARGS, jstring engine)
|
| return (jint)APR_SUCCESS;
|
| }
|
|
|
| +#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
| if (SSLeay() < 0x0090700L) {
|
| TCN_FREE_CSTRING(engine);
|
| tcn_ThrowAPRException(e, APR_EINVAL);
|
| ssl_initialized = 0;
|
| return (jint)APR_EINVAL;
|
| }
|
| +#endif
|
|
|
| -#ifndef OPENSSL_IS_BORINGSSL
|
| +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
| /* We must register the library in full, to ensure our configuration
|
| * code can successfully test the SSL environment.
|
| */
|
| - CRYPTO_malloc_init();
|
| + OPENSSL_malloc_init();
|
| #endif
|
|
|
| ERR_load_crypto_strings();
|
| @@ -663,7 +812,7 @@ TCN_IMPLEMENT_CALL(jint, SSL, initialize)(TCN_STDARGS, jstring engine)
|
| #if HAVE_ENGINE_LOAD_BUILTIN_ENGINES
|
| ENGINE_load_builtin_engines();
|
| #endif
|
| -#if OPENSSL_VERSION_NUMBER >= 0x00907001 && !defined(OPENSSL_IS_BORINGSSL)
|
| +#if OPENSSL_VERSION_NUMBER >= 0x00907001
|
| OPENSSL_load_builtin_modules();
|
| #endif
|
|
|
| @@ -703,17 +852,16 @@ TCN_IMPLEMENT_CALL(jint, SSL, initialize)(TCN_STDARGS, jstring engine)
|
| }
|
| #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() and SSL_get_app_data3() at request time */
|
| - SSL_init_app_data2_3_idx();
|
| + // For SSL_get_app_data*() at request time
|
| + SSL_init_app_data_idx();
|
| +
|
| +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
| + init_bio_methods();
|
| +#endif
|
|
|
| SSL_TMP_KEYS_INIT(r);
|
| if (r) {
|
| + ERR_clear_error();
|
| TCN_FREE_CSTRING(engine);
|
| ssl_init_cleanup(NULL);
|
| tcn_ThrowAPRException(e, APR_ENOTIMPL);
|
| @@ -727,299 +875,9 @@ TCN_IMPLEMENT_CALL(jint, SSL, initialize)(TCN_STDARGS, jstring engine)
|
| apr_pool_cleanup_null);
|
| TCN_FREE_CSTRING(engine);
|
|
|
| - // Cache the byte[].class for performance reasons
|
| - clazz = (*e)->FindClass(e, "[B");
|
| - byteArrayClass = (jclass) (*e)->NewGlobalRef(e, clazz);
|
| -
|
| - // Cache the String.class for performance reasons
|
| - sClazz = (*e)->FindClass(e, "java/lang/String");
|
| - stringClass = (jclass) (*e)->NewGlobalRef(e, sClazz);
|
| -
|
| 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(void, SSL, randSet)(TCN_STDARGS, jstring file)
|
| -{
|
| - TCN_ALLOC_CSTRING(file);
|
| - UNREFERENCED(o);
|
| - if (J2S(file)) {
|
| - ssl_global_rand_file = apr_pstrdup(tcn_global_pool, J2S(file));
|
| - }
|
| - TCN_FREE_CSTRING(file);
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jint, SSL, fipsModeGet)(TCN_STDARGS)
|
| -{
|
| - UNREFERENCED(o);
|
| -#ifdef OPENSSL_FIPS
|
| - return FIPS_mode();
|
| -#else
|
| - /* FIPS is unavailable */
|
| - tcn_ThrowException(e, "FIPS was not available to tcnative at build time. You will need to re-build tcnative against an OpenSSL with FIPS.");
|
| -
|
| - return 0;
|
| -#endif
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jint, SSL, fipsModeSet)(TCN_STDARGS, jint mode)
|
| -{
|
| - int r = 0;
|
| - UNREFERENCED(o);
|
| -
|
| -#ifdef OPENSSL_FIPS
|
| - if(1 != (r = (jint)FIPS_mode_set((int)mode))) {
|
| - /* arrange to get a human-readable error message */
|
| - unsigned long err = ERR_get_error();
|
| - char msg[256];
|
| -
|
| - /* ERR_load_crypto_strings() already called in initialize() */
|
| -
|
| - ERR_error_string_n(err, msg, 256);
|
| -
|
| - tcn_ThrowException(e, msg);
|
| - }
|
| -#else
|
| - /* FIPS is unavailable */
|
| - tcn_ThrowException(e, "FIPS was not available to tcnative at build time. You will need to re-build tcnative against an OpenSSL with FIPS.");
|
| -#endif
|
| -
|
| - return r;
|
| -}
|
| -
|
| -/* 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)
|
| -{
|
| - JNIEnv *e = NULL;
|
| - BIO_JAVA *j;
|
| -
|
| - if (bi == NULL)
|
| - return 0;
|
| - if (bi->ptr != NULL) {
|
| - j = (BIO_JAVA *)bi->ptr;
|
| - if (bi->init) {
|
| - bi->init = 0;
|
| - tcn_get_java_env(&e);
|
| - TCN_UNLOAD_CLASS(e, 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 = -1;
|
| -
|
| - if (b->init && in != NULL) {
|
| - BIO_JAVA *j = (BIO_JAVA *)b->ptr;
|
| - JNIEnv *e = NULL;
|
| - jbyteArray jb;
|
| - tcn_get_java_env(&e);
|
| - jb = (*e)->NewByteArray(e, inl);
|
| - if (!(*e)->ExceptionOccurred(e)) {
|
| - BIO_clear_retry_flags(b);
|
| - (*e)->SetByteArrayRegion(e, jb, 0, inl, (jbyte *)in);
|
| - ret = (*e)->CallIntMethod(e, j->cb.obj,
|
| - j->cb.mid[0], jb);
|
| - (*e)->DeleteLocalRef(e, jb);
|
| - }
|
| - }
|
| - if (ret == 0) {
|
| - BIO_set_retry_write(b);
|
| - ret = -1;
|
| - }
|
| - return ret;
|
| -}
|
| -
|
| -static int jbs_read(BIO *b, char *out, int outl)
|
| -{
|
| - jint ret = 0;
|
| - jbyte *jout;
|
| -
|
| - if (b->init && out != NULL) {
|
| - BIO_JAVA *j = (BIO_JAVA *)b->ptr;
|
| - JNIEnv *e = NULL;
|
| - jbyteArray jb;
|
| - tcn_get_java_env(&e);
|
| - jb = (*e)->NewByteArray(e, outl);
|
| - if (!(*e)->ExceptionOccurred(e)) {
|
| - BIO_clear_retry_flags(b);
|
| - ret = (*e)->CallIntMethod(e, j->cb.obj,
|
| - j->cb.mid[1], jb);
|
| - if (ret > 0) {
|
| - jout = (*e)->GetPrimitiveArrayCritical(e, jb, NULL);
|
| - memcpy(out, jout, ret);
|
| - (*e)->ReleasePrimitiveArrayCritical(e, jb, jout, 0);
|
| - } else if (outl != 0) {
|
| - ret = -1;
|
| - BIO_set_retry_read(b);
|
| - }
|
| - (*e)->DeleteLocalRef(e, jb);
|
| - }
|
| - }
|
| - return ret;
|
| -}
|
| -
|
| -static int jbs_puts(BIO *b, const char *in)
|
| -{
|
| - int ret = 0;
|
| - JNIEnv *e = NULL;
|
| - BIO_JAVA *j;
|
| -
|
| - if (b->init && in != NULL) {
|
| - j = (BIO_JAVA *)b->ptr;
|
| - tcn_get_java_env(&e);
|
| - 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;
|
| - JNIEnv *e = NULL;
|
| - BIO_JAVA *j;
|
| - jobject o;
|
| - int l;
|
| -
|
| - if (b->init && out != NULL) {
|
| - j = (BIO_JAVA *)b->ptr;
|
| - tcn_get_java_env(&e);
|
| - if ((o = (*e)->CallObjectMethod(e, j->cb.obj,
|
| - j->cb.mid[3], (jint)(outl - 1)))) {
|
| - TCN_ALLOC_CSTRING(o);
|
| - if (J2S(o)) {
|
| - 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)
|
| -{
|
| - int ret = 0;
|
| - switch (cmd) {
|
| - case BIO_CTRL_FLUSH:
|
| - ret = 1;
|
| - break;
|
| - default:
|
| - ret = 0;
|
| - break;
|
| - }
|
| - return ret;
|
| -}
|
| -
|
| -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, newMemBIO)(TCN_STDARGS)
|
| {
|
| BIO *bio = NULL;
|
| @@ -1029,138 +887,14 @@ TCN_IMPLEMENT_CALL(jlong, SSL, newMemBIO)(TCN_STDARGS)
|
| // TODO: Use BIO_s_secmem() once included in stable release
|
| if ((bio = BIO_new(BIO_s_mem())) == NULL) {
|
| tcn_ThrowException(e, "Create BIO failed");
|
| - return (jlong) NULL;
|
| - }
|
| - return P2J(bio);
|
| -}
|
| -
|
| -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 == 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);
|
| + return 0;
|
| }
|
| -
|
| - cls = (*e)->GetObjectClass(e, callback);
|
| - 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;
|
| -
|
| - if (b != NULL) {
|
| - 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(e,
|
| - tcn_password_callback.cb.obj);
|
| - }
|
| - cls = (*e)->GetObjectClass(e, callback);
|
| - 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];
|
| + char buf[ERR_LEN];
|
| UNREFERENCED(o);
|
| ERR_error_string(ERR_get_error(), buf);
|
| return tcn_new_string(e, buf);
|
| @@ -1205,14 +939,28 @@ TCN_IMPLEMENT_CALL(jlong /* SSL * */, SSL, newSSL)(TCN_STDARGS,
|
|
|
| UNREFERENCED_STDARGS;
|
|
|
| - handshakeCount = malloc(sizeof(int));
|
| ssl = SSL_new(c->ctx);
|
| if (ssl == NULL) {
|
| tcn_ThrowException(e, "cannot create new ssl");
|
| return 0;
|
| }
|
|
|
| + // Set the app_data2 before all the others because it may be used in SSL_free.
|
| + SSL_set_app_data2(ssl, c);
|
| +
|
| + // Initially we will share the configuration from the SSLContext.
|
| + // Set this before other app_data because there is no chance of failure, and if other app_data initialization fails
|
| + // SSL_free maybe called and the state of this variable is assumed to be initalized.
|
| + SSL_set_app_data4(ssl, &c->verify_config);
|
| +
|
| // Store the handshakeCount in the SSL instance.
|
| + handshakeCount = (int*) OPENSSL_malloc(sizeof(int));
|
| + if (handshakeCount == NULL) {
|
| + SSL_free(ssl);
|
| + tcn_ThrowException(e, "cannot create handshakeCount user data");
|
| + return 0;
|
| + }
|
| +
|
| *handshakeCount = 0;
|
| SSL_set_app_data3(ssl, handshakeCount);
|
|
|
| @@ -1225,33 +973,9 @@ TCN_IMPLEMENT_CALL(jlong /* SSL * */, SSL, newSSL)(TCN_STDARGS,
|
| SSL_set_connect_state(ssl);
|
| }
|
|
|
| - // Setup verify and seed
|
| - SSL_set_verify_result(ssl, X509_V_OK);
|
| - SSL_rand_seed(c->rand_file);
|
| -
|
| - // Store for later usage in SSL_callback_SSL_verify
|
| - SSL_set_app_data2(ssl, c);
|
| return P2J(ssl);
|
| }
|
|
|
| -TCN_IMPLEMENT_CALL(void, SSL, setBIO)(TCN_STDARGS,
|
| - jlong ssl /* SSL * */,
|
| - jlong rbio /* BIO * */,
|
| - jlong wbio /* BIO * */) {
|
| - SSL *ssl_ = J2P(ssl, SSL *);
|
| - BIO *r = J2P(rbio, BIO *);
|
| - BIO *w = J2P(wbio, BIO *);
|
| -
|
| - if (ssl_ == NULL) {
|
| - tcn_ThrowException(e, "ssl is null");
|
| - return;
|
| - }
|
| -
|
| - UNREFERENCED_STDARGS;
|
| -
|
| - SSL_set_bio(ssl_, r, w);
|
| -}
|
| -
|
| TCN_IMPLEMENT_CALL(jint, SSL, getError)(TCN_STDARGS,
|
| jlong ssl /* SSL * */,
|
| jint ret) {
|
| @@ -1267,78 +991,69 @@ TCN_IMPLEMENT_CALL(jint, SSL, getError)(TCN_STDARGS,
|
| return SSL_get_error(ssl_, ret);
|
| }
|
|
|
| -// How much did SSL write into this BIO?
|
| -TCN_IMPLEMENT_CALL(jint /* nbytes */, SSL, pendingWrittenBytesInBIO)(TCN_STDARGS,
|
| - jlong bio /* BIO * */) {
|
| - BIO *b = J2P(bio, BIO *);
|
| -
|
| - if (b == NULL) {
|
| - tcn_ThrowException(e, "bio is null");
|
| - return 0;
|
| - }
|
| -
|
| - UNREFERENCED_STDARGS;
|
| -
|
| - return BIO_ctrl_pending(b);
|
| -}
|
| -
|
| -// How much is available for reading in the given SSL struct?
|
| -TCN_IMPLEMENT_CALL(jint, SSL, pendingReadableBytesInSSL)(TCN_STDARGS, jlong ssl /* SSL * */) {
|
| - SSL *ssl_ = J2P(ssl, SSL *);
|
| -
|
| - if (ssl_ == NULL) {
|
| - tcn_ThrowException(e, "ssl is null");
|
| - return 0;
|
| - }
|
| -
|
| - UNREFERENCED_STDARGS;
|
| -
|
| - return SSL_pending(ssl_);
|
| -}
|
| -
|
| // Write wlen bytes from wbuf into bio
|
| -TCN_IMPLEMENT_CALL(jint /* status */, SSL, writeToBIO)(TCN_STDARGS,
|
| - jlong bio /* BIO * */,
|
| - jlong wbuf /* char* */,
|
| - jint wlen /* sizeof(wbuf) */) {
|
| - BIO *b = J2P(bio, BIO *);
|
| - void *w = J2P(wbuf, void *);
|
| -
|
| - if (b == NULL) {
|
| +TCN_IMPLEMENT_CALL(jint /* status */, SSL, bioWrite)(TCN_STDARGS,
|
| + jlong bioAddress /* BIO* */,
|
| + jlong wbufAddress /* char* */,
|
| + jint wlen /* sizeof(wbuf) */) {
|
| + BIO* bio = J2P(bioAddress, BIO*);
|
| + void* wbuf = J2P(wbufAddress, void*);
|
| +
|
| + if (bio == NULL) {
|
| tcn_ThrowException(e, "bio is null");
|
| return 0;
|
| }
|
| - if (w == NULL) {
|
| + if (wbuf == NULL) {
|
| tcn_ThrowException(e, "wbuf is null");
|
| return 0;
|
| }
|
|
|
| UNREFERENCED_STDARGS;
|
|
|
| - return BIO_write(b, w, wlen);
|
| -
|
| + return BIO_write(bio, wbuf, wlen);
|
| }
|
|
|
| -// Read up to rlen bytes from bio into rbuf
|
| -TCN_IMPLEMENT_CALL(jint /* status */, SSL, readFromBIO)(TCN_STDARGS,
|
| - jlong bio /* BIO * */,
|
| - jlong rbuf /* char * */,
|
| - jint rlen /* sizeof(rbuf) - 1 */) {
|
| - BIO *b = J2P(bio, BIO *);
|
| - void *r = J2P(rbuf, void *);
|
| +TCN_IMPLEMENT_CALL(void, SSL, bioSetByteBuffer)(TCN_STDARGS,
|
| + jlong bioAddress /* BIO* */,
|
| + jlong bufferAddress /* Address for direct memory */,
|
| + jint maxUsableBytes /* max number of bytes to use */,
|
| + jboolean isSSLWriteSink) {
|
| + BIO* bio = J2P(bioAddress, BIO*);
|
| + char* buffer = J2P(bufferAddress, char*);
|
| + struct TCN_bio_bytebuffer* bioUserData = NULL;
|
| + TCN_ASSERT(bio != NULL);
|
| + TCN_ASSERT(buffer != NULL);
|
| +
|
| + bioUserData = (struct TCN_bio_bytebuffer*) BIO_get_data(bio);
|
| + TCN_ASSERT(bioUserData != NULL);
|
| +
|
| + bioUserData->buffer = buffer;
|
| + bioUserData->bufferLength = maxUsableBytes;
|
| + bioUserData->bufferIsSSLWriteSink = (bool) isSSLWriteSink;
|
| +}
|
|
|
| - if (b == NULL) {
|
| - tcn_ThrowException(e, "bio is null");
|
| - return 0;
|
| - }
|
| - if (r == NULL) {
|
| - tcn_ThrowException(e, "rbuf is null");
|
| - return 0;
|
| +TCN_IMPLEMENT_CALL(void, SSL, bioClearByteBuffer)(TCN_STDARGS, jlong bioAddress) {
|
| + BIO* bio = J2P(bioAddress, BIO*);
|
| + struct TCN_bio_bytebuffer* bioUserData = NULL;
|
| +
|
| + if (bio == NULL || (bioUserData = (struct TCN_bio_bytebuffer*) BIO_get_data(bio)) == NULL) {
|
| + return;
|
| }
|
|
|
| - UNREFERENCED_STDARGS;
|
| + bioUserData->buffer = NULL;
|
| + bioUserData->bufferLength = 0;
|
| + bioUserData->bufferIsSSLWriteSink = false;
|
| +}
|
| +
|
| +TCN_IMPLEMENT_CALL(jint, SSL, bioFlushByteBuffer)(TCN_STDARGS, jlong bioAddress) {
|
| + BIO* bio = J2P(bioAddress, BIO*);
|
| + struct TCN_bio_bytebuffer* bioUserData;
|
|
|
| - return BIO_read(b, r, rlen);
|
| + return (bio == NULL ||
|
| + (bioUserData = (struct TCN_bio_bytebuffer*) BIO_get_data(bio)) == NULL ||
|
| + bioUserData->nonApplicationBufferLength == 0 ||
|
| + bioUserData->buffer == NULL ||
|
| + !bioUserData->bufferIsSSLWriteSink) ? 0 : tcn_flush_sslbuffer_to_bytebuffer(bioUserData);
|
| }
|
|
|
| // Write up to wlen bytes of application data to the ssl BIO (encrypt)
|
| @@ -1420,43 +1135,74 @@ TCN_IMPLEMENT_CALL(void, SSL, setShutdown)(TCN_STDARGS,
|
| TCN_IMPLEMENT_CALL(void, SSL, freeSSL)(TCN_STDARGS,
|
| jlong ssl /* SSL * */) {
|
| int *handshakeCount = NULL;
|
| + tcn_ssl_ctxt_t* c = NULL;
|
| + tcn_ssl_verify_config_t* verify_config = NULL;
|
| SSL *ssl_ = J2P(ssl, SSL *);
|
| if (ssl_ == NULL) {
|
| tcn_ThrowException(e, "ssl is null");
|
| return;
|
| }
|
| + c = SSL_get_app_data2(ssl_);
|
| handshakeCount = SSL_get_app_data3(ssl_);
|
| + verify_config = SSL_get_app_data4(ssl_);
|
|
|
| UNREFERENCED_STDARGS;
|
| + TCN_ASSERT(c != NULL);
|
|
|
| if (handshakeCount != NULL) {
|
| - free(handshakeCount);
|
| + OPENSSL_free(handshakeCount);
|
| + SSL_set_app_data3(ssl_, NULL);
|
| + }
|
| +
|
| + // Only free the verify_config if it is not shared with the SSLContext.
|
| + if (verify_config != NULL && verify_config != &c->verify_config) {
|
| + OPENSSL_free(verify_config);
|
| + SSL_set_app_data4(ssl_, &c->verify_config);
|
| }
|
| SSL_free(ssl_);
|
| }
|
|
|
| -// Make a BIO pair (network and internal) for the provided SSL * and return the network BIO
|
| -TCN_IMPLEMENT_CALL(jlong, SSL, makeNetworkBIO)(TCN_STDARGS,
|
| - jlong ssl /* SSL * */) {
|
| - SSL *ssl_ = J2P(ssl, SSL *);
|
| - BIO *internal_bio;
|
| - BIO *network_bio;
|
| +TCN_IMPLEMENT_CALL(jlong, SSL, bioNewByteBuffer)(TCN_STDARGS,
|
| + jlong ssl /* SSL* */,
|
| + jint nonApplicationBufferSize) {
|
| + SSL* ssl_ = J2P(ssl, SSL*);
|
| + BIO* bio;
|
| + struct TCN_bio_bytebuffer* bioUserData;
|
|
|
| if (ssl_ == NULL) {
|
| tcn_ThrowException(e, "ssl is null");
|
| return 0;
|
| }
|
|
|
| - if (BIO_new_bio_pair(&internal_bio, 0, &network_bio, 0) != 1) {
|
| - tcn_ThrowException(e, "BIO_new_bio_pair failed");
|
| + if (nonApplicationBufferSize <= 0) {
|
| + tcn_ThrowException(e, "nonApplicationBufferSize <= 0");
|
| return 0;
|
| }
|
|
|
| - UNREFERENCED(o);
|
| + bio = BIO_new(BIO_java_bytebuffer());
|
| + if (bio == NULL) {
|
| + tcn_ThrowException(e, "BIO_new failed");
|
| + return 0;
|
| + }
|
| +
|
| + bioUserData = BIO_get_data(bio);
|
| + if (bioUserData == NULL) {
|
| + BIO_free(bio);
|
| + tcn_ThrowException(e, "BIO_get_data failed");
|
| + return 0;
|
| + }
|
| +
|
| + bioUserData->nonApplicationBuffer = (char*) OPENSSL_malloc(nonApplicationBufferSize * sizeof(char));
|
| + if (bioUserData->nonApplicationBuffer == NULL) {
|
| + BIO_free(bio);
|
| + tcn_Throw(e, "Failed to allocate internal buffer of size %d", nonApplicationBufferSize);
|
| + return 0;
|
| + }
|
| + bioUserData->nonApplicationBufferSize = nonApplicationBufferSize;
|
|
|
| - SSL_set_bio(ssl_, internal_bio, internal_bio);
|
| + SSL_set_bio(ssl_, bio, bio);
|
|
|
| - return P2J(network_bio);
|
| + return P2J(bio);
|
| }
|
|
|
| // Free a BIO * (typically, the network BIO)
|
| @@ -1614,6 +1360,7 @@ TCN_IMPLEMENT_CALL(jobjectArray, SSL, getPeerCertChain)(TCN_STDARGS,
|
| unsigned char *buf;
|
| jobjectArray array;
|
| jbyteArray bArray;
|
| + jclass byteArrayClass = tcn_get_byte_array_class();
|
|
|
| SSL *ssl_ = J2P(ssl, SSL *);
|
|
|
| @@ -1627,7 +1374,7 @@ TCN_IMPLEMENT_CALL(jobjectArray, SSL, getPeerCertChain)(TCN_STDARGS,
|
| // Get a stack of all certs in the chain.
|
| sk = SSL_get_peer_cert_chain(ssl_);
|
|
|
| - len = sk_num((_STACK*) sk);
|
| + len = sk_X509_num(sk);
|
| if (len <= 0) {
|
| // No peer certificate chain as no auth took place yet, or the auth was not successful.
|
| return NULL;
|
| @@ -1636,12 +1383,14 @@ TCN_IMPLEMENT_CALL(jobjectArray, SSL, getPeerCertChain)(TCN_STDARGS,
|
| array = (*e)->NewObjectArray(e, len, byteArrayClass, NULL);
|
|
|
| for(i = 0; i < len; i++) {
|
| - cert = (X509*) sk_value((_STACK*) sk, i);
|
| + cert = sk_X509_value(sk, i);
|
|
|
| buf = NULL;
|
| length = i2d_X509(cert, &buf);
|
| if (length < 0) {
|
| - OPENSSL_free(buf);
|
| + if (buf != NULL) {
|
| + OPENSSL_free(buf);
|
| + }
|
| // In case of error just return an empty byte[][]
|
| return (*e)->NewObjectArray(e, 0, byteArrayClass, NULL);
|
| }
|
| @@ -1698,7 +1447,7 @@ TCN_IMPLEMENT_CALL(jbyteArray, SSL, getPeerCertificate)(TCN_STDARGS,
|
|
|
| TCN_IMPLEMENT_CALL(jstring, SSL, getErrorString)(TCN_STDARGS, jlong number)
|
| {
|
| - char buf[256];
|
| + char buf[ERR_LEN];
|
| UNREFERENCED(o);
|
| ERR_error_string(number, buf);
|
| return tcn_new_string(e, buf);
|
| @@ -1773,11 +1522,10 @@ TCN_IMPLEMENT_CALL(jlong, SSL, setTimeout)(TCN_STDARGS, jlong ssl, jlong seconds
|
| }
|
|
|
|
|
| -TCN_IMPLEMENT_CALL(void, SSL, setVerify)(TCN_STDARGS, jlong ssl,
|
| - jint level, jint depth)
|
| +TCN_IMPLEMENT_CALL(void, SSL, setVerify)(TCN_STDARGS, jlong ssl, jint level, jint depth)
|
| {
|
| - tcn_ssl_ctxt_t *c;
|
| - int verify;
|
| + tcn_ssl_verify_config_t* verify_config;
|
| + tcn_ssl_ctxt_t* c;
|
| SSL *ssl_ = J2P(ssl, SSL *);
|
|
|
| if (ssl_ == NULL) {
|
| @@ -1786,36 +1534,27 @@ TCN_IMPLEMENT_CALL(void, SSL, setVerify)(TCN_STDARGS, jlong ssl,
|
| }
|
|
|
| c = SSL_get_app_data2(ssl_);
|
| -
|
| - verify = SSL_VERIFY_NONE;
|
| + verify_config = SSL_get_app_data4(ssl_);
|
|
|
| UNREFERENCED(o);
|
| - TCN_ASSERT(c->ctx != 0);
|
| - c->verify_mode = level;
|
| + TCN_ASSERT(c != NULL);
|
| + TCN_ASSERT(verify_config != NULL);
|
|
|
| - if (c->verify_mode == SSL_CVERIFY_UNSET)
|
| - c->verify_mode = SSL_CVERIFY_NONE;
|
| - if (depth > 0)
|
| - c->verify_depth = depth;
|
| - /*
|
| - * Configure callbacks for SSL context
|
| - */
|
| - if (c->verify_mode == SSL_CVERIFY_REQUIRE)
|
| - verify |= SSL_VERIFY_PEER_STRICT;
|
| - if ((c->verify_mode == SSL_CVERIFY_OPTIONAL) ||
|
| - (c->verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA))
|
| - verify |= SSL_VERIFY_PEER;
|
| - if (!c->store) {
|
| - if (SSL_CTX_set_default_verify_paths(c->ctx)) {
|
| - c->store = SSL_CTX_get_cert_store(c->ctx);
|
| - X509_STORE_set_flags(c->store, 0);
|
| - }
|
| - else {
|
| - /* XXX: See if this is fatal */
|
| - }
|
| + // If we are sharing the configuration from the SSLContext we now need to create a new configuration just for this SSL.
|
| + if (verify_config == &c->verify_config) {
|
| + verify_config = (tcn_ssl_verify_config_t*) OPENSSL_malloc(sizeof(tcn_ssl_verify_config_t));
|
| + if (verify_config == NULL) {
|
| + tcn_ThrowException(e, "failed to allocate tcn_ssl_verify_config_t");
|
| + return;
|
| + }
|
| + // Copy the verify depth form the context in case depth is <0.
|
| + verify_config->verify_depth = c->verify_config.verify_depth;
|
| + SSL_set_app_data4(ssl_, verify_config);
|
| }
|
|
|
| - SSL_set_verify(ssl_, verify, SSL_callback_SSL_verify);
|
| + // No need to specify a callback for SSL_set_verify because we override the default certificate verification via SSL_CTX_set_cert_verify_callback.
|
| + SSL_set_verify(ssl_, tcn_set_verify_config(verify_config, level, depth), NULL);
|
| + SSL_set_verify_depth(ssl_, verify_config->verify_depth);
|
| }
|
|
|
| TCN_IMPLEMENT_CALL(void, SSL, setOptions)(TCN_STDARGS, jlong ssl,
|
| @@ -1830,15 +1569,24 @@ TCN_IMPLEMENT_CALL(void, SSL, setOptions)(TCN_STDARGS, jlong ssl,
|
|
|
| UNREFERENCED_STDARGS;
|
|
|
| -#ifndef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
|
| - /* Clear the flag if not supported */
|
| - if (opt & 0x00040000) {
|
| - opt &= ~0x00040000;
|
| - }
|
| -#endif
|
| SSL_set_options(ssl_, opt);
|
| }
|
|
|
| +TCN_IMPLEMENT_CALL(void, SSL, clearOptions)(TCN_STDARGS, jlong ssl,
|
| + jint opt)
|
| +{
|
| + SSL *ssl_ = J2P(ssl, SSL *);
|
| +
|
| + if (ssl_ == NULL) {
|
| + tcn_ThrowException(e, "ssl is null");
|
| + return;
|
| + }
|
| +
|
| + UNREFERENCED_STDARGS;
|
| +
|
| + SSL_clear_options(ssl_, opt);
|
| +}
|
| +
|
| TCN_IMPLEMENT_CALL(jint, SSL, getOptions)(TCN_STDARGS, jlong ssl)
|
| {
|
| SSL *ssl_ = J2P(ssl, SSL *);
|
| @@ -1858,7 +1606,7 @@ TCN_IMPLEMENT_CALL(jobjectArray, SSL, getCiphers)(TCN_STDARGS, jlong ssl)
|
| STACK_OF(SSL_CIPHER) *sk;
|
| int len;
|
| jobjectArray array;
|
| - SSL_CIPHER *cipher;
|
| + const SSL_CIPHER *cipher;
|
| const char *name;
|
| int i;
|
| jstring c_name;
|
| @@ -1872,7 +1620,7 @@ TCN_IMPLEMENT_CALL(jobjectArray, SSL, getCiphers)(TCN_STDARGS, jlong ssl)
|
| UNREFERENCED_STDARGS;
|
|
|
| sk = SSL_get_ciphers(ssl_);
|
| - len = sk_num((_STACK*) sk);
|
| + len = sk_SSL_CIPHER_num(sk);
|
|
|
| if (len <= 0) {
|
| // No peer certificate chain as no auth took place yet, or the auth was not successful.
|
| @@ -1880,10 +1628,10 @@ TCN_IMPLEMENT_CALL(jobjectArray, SSL, getCiphers)(TCN_STDARGS, jlong ssl)
|
| }
|
|
|
| // Create the byte[][]Â array that holds all the certs
|
| - array = (*e)->NewObjectArray(e, len, stringClass, NULL);
|
| + array = (*e)->NewObjectArray(e, len, tcn_get_string_class(), NULL);
|
|
|
| for (i = 0; i < len; i++) {
|
| - cipher = (SSL_CIPHER*) sk_value((_STACK*) sk, i);
|
| + cipher = sk_SSL_CIPHER_value(sk, i);
|
| name = SSL_CIPHER_get_name(cipher);
|
|
|
| c_name = (*e)->NewStringUTF(e, name);
|
| @@ -1911,7 +1659,7 @@ TCN_IMPLEMENT_CALL(jboolean, SSL, setCipherSuites)(TCN_STDARGS, jlong ssl,
|
| }
|
|
|
| if (!SSL_set_cipher_list(ssl_, J2S(ciphers))) {
|
| - char err[256];
|
| + char err[ERR_LEN];
|
| ERR_error_string(ERR_get_error(), err);
|
| tcn_Throw(e, "Unable to configure permitted SSL ciphers (%s)", err);
|
| rv = JNI_FALSE;
|
| @@ -1965,10 +1713,7 @@ TCN_IMPLEMENT_CALL(jint, SSL, getHandshakeCount)(TCN_STDARGS, jlong ssl)
|
| UNREFERENCED(o);
|
|
|
| handshakeCount = SSL_get_app_data3(ssl_);
|
| - if (handshakeCount != NULL) {
|
| - return *handshakeCount;
|
| - }
|
| - return 0;
|
| + return handshakeCount != NULL ? *handshakeCount : 0;
|
| }
|
|
|
|
|
| @@ -2007,420 +1752,238 @@ TCN_IMPLEMENT_CALL(void, SSL, setState)(TCN_STDARGS,
|
| SSL_set_state(ssl_, state);
|
| }
|
|
|
| +TCN_IMPLEMENT_CALL(void, SSL, setTlsExtHostName)(TCN_STDARGS, jlong ssl, jstring hostname) {
|
| + TCN_ALLOC_CSTRING(hostname);
|
| + SSL *ssl_ = J2P(ssl, SSL *);
|
|
|
| -/*** End Apple API Additions ***/
|
| -
|
| -#else
|
| -#error OpenSSL is required!
|
| -
|
| -/* OpenSSL is not supported.
|
| - * Create empty stubs.
|
| - */
|
| -
|
| -TCN_IMPLEMENT_CALL(jint, SSL, version)(TCN_STDARGS)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - return 0;
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jstring, SSL, versionString)(TCN_STDARGS)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - return NULL;
|
| -}
|
| + if (ssl_ == NULL) {
|
| + tcn_ThrowException(e, "ssl is null");
|
| + } else {
|
| + UNREFERENCED(o);
|
|
|
| -TCN_IMPLEMENT_CALL(jint, SSL, initialize)(TCN_STDARGS, jstring engine)
|
| -{
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(engine);
|
| - tcn_ThrowAPRException(e, APR_ENOTIMPL);
|
| - return (jint)APR_ENOTIMPL;
|
| -}
|
| + if (SSL_set_tlsext_host_name(ssl_, J2S(hostname)) != 1) {
|
| + char err[ERR_LEN];
|
| + ERR_error_string(ERR_get_error(), err);
|
| + tcn_Throw(e, "Unable to set TLS servername extension (%s)", err);
|
| + }
|
| + }
|
|
|
| -TCN_IMPLEMENT_CALL(jboolean, SSL, randLoad)(TCN_STDARGS, jstring file)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(file);
|
| - return JNI_FALSE;
|
| + TCN_FREE_CSTRING(hostname);
|
| }
|
|
|
| -TCN_IMPLEMENT_CALL(jboolean, SSL, randSave)(TCN_STDARGS, jstring file)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - return JNI_FALSE;
|
| -}
|
| +TCN_IMPLEMENT_CALL(void, SSL, setHostNameValidation)(TCN_STDARGS, jlong sslAddress, jint flags, jstring hostnameString) {
|
| + SSL* ssl = J2P(sslAddress, SSL*);
|
|
|
| -TCN_IMPLEMENT_CALL(jboolean, SSL, randMake)(TCN_STDARGS, jstring file,
|
| - jint length, jboolean base64)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(file);
|
| - UNREFERENCED(length);
|
| - UNREFERENCED(base64);
|
| - return JNI_FALSE;
|
| + if (ssl == NULL) {
|
| + tcn_ThrowException(e, "ssl is null");
|
| + } else {
|
| + const char* hostname = hostnameString == NULL ? NULL : (*e)->GetStringUTFChars(e, hostnameString, 0);
|
| +#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
|
| + X509_VERIFY_PARAM* param = SSL_get0_param(ssl);
|
| + X509_VERIFY_PARAM_set_hostflags(param, flags);
|
| + if (X509_VERIFY_PARAM_set1_host(param, hostname, 0) != 1) {
|
| + char err[ERR_LEN];
|
| + ERR_error_string(ERR_get_error(), err);
|
| + tcn_Throw(e, "X509_VERIFY_PARAM_set1_host error (%s)", err);
|
| + }
|
| +#else
|
| + if (hostname != NULL && hostname[0] != '\0') {
|
| + tcn_ThrowException(e, "hostname verification requires OpenSSL 1.0.2+");
|
| + }
|
| +#endif
|
| + (*e)->ReleaseStringUTFChars(e, hostnameString, hostname);
|
| + }
|
| }
|
|
|
| -TCN_IMPLEMENT_CALL(void, SSL, randSet)(TCN_STDARGS, jstring file)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(file);
|
| -}
|
| +TCN_IMPLEMENT_CALL(jobjectArray, SSL, authenticationMethods)(TCN_STDARGS, jlong ssl) {
|
| + SSL *ssl_ = J2P(ssl, SSL *);
|
| + const STACK_OF(SSL_CIPHER) *ciphers = NULL;
|
| + int len;
|
| + int i;
|
| + jobjectArray array;
|
|
|
| -TCN_IMPLEMENT_CALL(jint, SSL, fipsModeGet)(TCN_STDARGS)
|
| -{
|
| - UNREFERENCED(o);
|
| - tcn_ThrowException(e, "FIPS was not available to tcnative at build time. You will need to re-build tcnative against an OpenSSL with FIPS.");
|
| - return 0;
|
| -}
|
| + TCN_ASSERT(ssl_ != NULL);
|
|
|
| -TCN_IMPLEMENT_CALL(jint, SSL, fipsModeSet)(TCN_STDARGS, jint mode)
|
| -{
|
| UNREFERENCED(o);
|
| - UNREFERENCED(mode);
|
| - tcn_ThrowException(e, "FIPS was not available to tcnative at build time. You will need to re-build tcnative against an OpenSSL with FIPS.");
|
| - return 0;
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jlong, SSL, newBIO)(TCN_STDARGS, jlong pool,
|
| - jobject callback)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(pool);
|
| - UNREFERENCED(callback);
|
| - return 0;
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jlong, SSL, newMemBIO)(TCN_STDARGS)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - return 0;
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jint, SSL, closeBIO)(TCN_STDARGS, jlong bio)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(bio);
|
| - return (jint)APR_ENOTIMPL;
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(void, SSL, setPasswordCallback)(TCN_STDARGS,
|
| - jobject callback)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(callback);
|
| -}
|
|
|
| -TCN_IMPLEMENT_CALL(void, SSL, setPassword)(TCN_STDARGS, jstring password)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(password);
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jboolean, SSL, generateRSATempKey)(TCN_STDARGS, jint idx)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(idx);
|
| - return JNI_FALSE;
|
| -}
|
| + ciphers = SSL_get_ciphers(ssl_);
|
| + len = sk_SSL_CIPHER_num(ciphers);
|
|
|
| -TCN_IMPLEMENT_CALL(jboolean, SSL, loadDSATempKey)(TCN_STDARGS, jint idx,
|
| - jstring file)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(idx);
|
| - UNREFERENCED(file);
|
| - return JNI_FALSE;
|
| -}
|
| + array = (*e)->NewObjectArray(e, len, tcn_get_string_class(), NULL);
|
|
|
| -TCN_IMPLEMENT_CALL(jstring, SSL, getLastError)(TCN_STDARGS)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - return NULL;
|
| + for (i = 0; i < len; i++) {
|
| + (*e)->SetObjectArrayElement(e, array, i,
|
| + (*e)->NewStringUTF(e, SSL_cipher_authentication_method((SSL_CIPHER*) sk_value((_STACK*) ciphers, i))));
|
| + }
|
| + return array;
|
| }
|
|
|
| -TCN_IMPLEMENT_CALL(jboolean, SSL, hasOp)(TCN_STDARGS, jint op)
|
| +TCN_IMPLEMENT_CALL(void, SSL, setCertificateBio)(TCN_STDARGS, jlong ssl,
|
| + jlong cert, jlong key,
|
| + jstring password)
|
| {
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(op);
|
| - return JNI_FALSE;
|
| -}
|
| -
|
| -/*** Begin Twitter 1:1 API addition ***/
|
| -TCN_IMPLEMENT_CALL(jint, SSL, getLastErrorNumber)(TCN_STDARGS) {
|
| - UNREFERENCED(o);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jlong, SSL, newSSL)(TCN_STDARGS, jlong ssl_ctx) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl_ctx);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(void, SSL, setBIO)(TCN_STDARGS, jlong ssl, jlong rbio, jlong wbio) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - UNREFERENCED(rbio);
|
| - UNREFERENCED(wbio);
|
| - tcn_ThrowException(e, "Not implemented");
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jint, SSL, pendingWrittenBytesInBIO)(TCN_STDARGS, jlong bio) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(bio);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jint, SSL, pendingReadableBytesInSSL)(TCN_STDARGS, jlong ssl) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jint, SSL, writeToBIO)(TCN_STDARGS, jlong bio, jlong wbuf, jint wlen) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(bio);
|
| - UNREFERENCED(wbuf);
|
| - UNREFERENCED(wlen);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jint, SSL, readFromBIO)(TCN_STDARGS, jlong bio, jlong rbuf, jint rlen) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(bio);
|
| - UNREFERENCED(rbuf);
|
| - UNREFERENCED(rlen);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jint, SSL, writeToSSL)(TCN_STDARGS, jlong ssl, jlong wbuf, jint wlen) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - UNREFERENCED(wbuf);
|
| - UNREFERENCED(wlen);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(jint, SSL, readFromSSL)(TCN_STDARGS, jlong ssl, jlong rbuf, jint rlen) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - UNREFERENCED(rbuf);
|
| - UNREFERENCED(rlen);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| + SSL *ssl_ = J2P(ssl, SSL *);
|
| + BIO *cert_bio = J2P(cert, BIO *);
|
| + BIO *key_bio = J2P(key, BIO *);
|
| + EVP_PKEY* pkey = NULL;
|
| + X509* xcert = NULL;
|
| + TCN_ALLOC_CSTRING(password);
|
| + char err[ERR_LEN];
|
|
|
| -TCN_IMPLEMENT_CALL(jint, SSL, getShutdown)(TCN_STDARGS, jlong ssl) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| + UNREFERENCED(o);
|
| + TCN_ASSERT(ssl != NULL);
|
|
|
| -TCN_IMPLEMENT_CALL(void, SSL, setShutdown)(TCN_STDARGS, jlong ssl, jint mode) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - UNREFERENCED(mode);
|
| - tcn_ThrowException(e, "Not implemented");
|
| -}
|
| + if (key <= 0) {
|
| + key = cert;
|
| + }
|
|
|
| -TCN_IMPLEMENT_CALL(void, SSL, freeSSL)(TCN_STDARGS, jlong ssl) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| -}
|
| + if (cert <= 0 || key <= 0) {
|
| + tcn_Throw(e, "No Certificate file specified or invalid file format");
|
| + goto cleanup;
|
| + }
|
|
|
| -TCN_IMPLEMENT_CALL(jlong, SSL, makeNetworkBIO)(TCN_STDARGS, jlong ssl) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| + if ((pkey = load_pem_key_bio(cpassword, key_bio)) == NULL) {
|
| + ERR_error_string_n(ERR_get_error(), err, ERR_LEN);
|
| + ERR_clear_error();
|
| + tcn_Throw(e, "Unable to load certificate key (%s)",err);
|
| + goto cleanup;
|
| + }
|
| + if ((xcert = load_pem_cert_bio(cpassword, cert_bio)) == NULL) {
|
| + ERR_error_string_n(ERR_get_error(), err, ERR_LEN);
|
| + ERR_clear_error();
|
| + tcn_Throw(e, "Unable to load certificate (%s) ", err);
|
| + goto cleanup;
|
| + }
|
|
|
| -TCN_IMPLEMENT_CALL(void, SSL, freeBIO)(TCN_STDARGS, jlong bio) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(bio);
|
| - tcn_ThrowException(e, "Not implemented");
|
| -}
|
| + if (SSL_use_certificate(ssl_, xcert) <= 0) {
|
| + ERR_error_string_n(ERR_get_error(), err, ERR_LEN);
|
| + ERR_clear_error();
|
| + tcn_Throw(e, "Error setting certificate (%s)", err);
|
| + goto cleanup;
|
| + }
|
| + if (SSL_use_PrivateKey(ssl_, pkey) <= 0) {
|
| + ERR_error_string_n(ERR_get_error(), err, ERR_LEN);
|
| + ERR_clear_error();
|
| + tcn_Throw(e, "Error setting private key (%s)", err);
|
| + goto cleanup;
|
| + }
|
| + if (SSL_check_private_key(ssl_) <= 0) {
|
| + ERR_error_string_n(ERR_get_error(), err, ERR_LEN);
|
| + ERR_clear_error();
|
|
|
| -TCN_IMPLEMENT_CALL(jint, SSL, shutdownSSL)(TCN_STDARGS, jlong ssl) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| + tcn_Throw(e, "Private key does not match the certificate public key (%s)",
|
| + err);
|
| + goto cleanup;
|
| + }
|
| +cleanup:
|
| + TCN_FREE_CSTRING(password);
|
| + EVP_PKEY_free(pkey); // this function is safe to call with NULL
|
| + X509_free(xcert); // this function is safe to call with NULL
|
| }
|
|
|
| -TCN_IMPLEMENT_CALL(jstring, SSL, getCipherForSSL)(TCN_STDARGS, jlong ssl) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return NULL;
|
| -}
|
| +TCN_IMPLEMENT_CALL(void, SSL, setCertificateChainBio)(TCN_STDARGS, jlong ssl,
|
| + jlong chain,
|
| + jboolean skipfirst)
|
| +{
|
| + SSL *ssl_ = J2P(ssl, SSL *);
|
| + BIO *b = J2P(chain, BIO *);
|
| + char err[ERR_LEN];
|
|
|
| -TCN_IMPLEMENT_CALL(jint, SSL, isInInit)(TCN_STDARGS, jlong ssl) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| + UNREFERENCED(o);
|
| + TCN_ASSERT(ssl_ != NULL);
|
| + TCN_ASSERT(b != NULL);
|
|
|
| -TCN_IMPLEMENT_CALL(jint, SSL, doHandshake)(TCN_STDARGS, jlong ssl) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| + if (SSL_use_certificate_chain_bio(ssl_, b, skipfirst) < 0) {
|
| + ERR_error_string_n(ERR_get_error(), err, ERR_LEN);
|
| + ERR_clear_error();
|
| + tcn_Throw(e, "Error setting certificate chain (%s)", err);
|
| + }
|
| }
|
|
|
| -TCN_IMPLEMENT_CALL(jstring, SSL, getNextProtoNegotiated)(TCN_STDARGS, jlong ssl) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return NULL;
|
| -}
|
| +TCN_IMPLEMENT_CALL(long, SSL, parsePrivateKey)(TCN_STDARGS, jlong privateKeyBio, jstring password)
|
| +{
|
| + EVP_PKEY* pkey = NULL;
|
| + BIO *bio = J2P(privateKeyBio, BIO *);
|
| + TCN_ALLOC_CSTRING(password);
|
| + char err[ERR_LEN];
|
|
|
| -/*** End Twitter 1:1 API addition ***/
|
| + UNREFERENCED(o);
|
|
|
| -/*** Begin Apple 1:1 API addition ***/
|
| + if (bio == NULL) {
|
| + tcn_Throw(e, "Unable to load certificate key");
|
| + goto cleanup;
|
| + }
|
|
|
| -TCN_IMPLEMENT_CALL(jstring, SSL, getAlpnSelected)(TCN_STDARGS, jlong ssl) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return NULL;
|
| -}
|
| + if ((pkey = load_pem_key_bio(cpassword, bio)) == NULL) {
|
| + ERR_error_string_n(ERR_get_error(), err, ERR_LEN);
|
| + ERR_clear_error();
|
| + tcn_Throw(e, "Unable to load certificate key (%s)",err);
|
| + goto cleanup;
|
| + }
|
|
|
| -TCN_IMPLEMENT_CALL(jobjectArray, SSL, getPeerCertChain)(TCN_STDARGS, jlong ssl)
|
| -{
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return NULL;
|
| +cleanup:
|
| + TCN_FREE_CSTRING(password);
|
| + return P2J(pkey);
|
| }
|
|
|
| -TCN_IMPLEMENT_CALL(jbyteArray, SSL, getPeerCertificate)(TCN_STDARGS, jlong ssl)
|
| +TCN_IMPLEMENT_CALL(void, SSL, freePrivateKey)(TCN_STDARGS, jlong privateKey)
|
| {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return NULL;
|
| + EVP_PKEY *key = J2P(privateKey, EVP_PKEY *);
|
| + UNREFERENCED(o);
|
| + EVP_PKEY_free(key); // Safe to call with NULL as well.
|
| }
|
|
|
| -TCN_IMPLEMENT_CALL(jstring, SSL, getErrorString)(TCN_STDARGS, jlong number)
|
| +TCN_IMPLEMENT_CALL(long, SSL, parseX509Chain)(TCN_STDARGS, jlong x509ChainBio)
|
| {
|
| - UNREFERENCED(o);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return NULL;
|
| -}
|
| + BIO *cert_bio = J2P(x509ChainBio, BIO *);
|
| + X509* cert = NULL;
|
| + STACK_OF(X509) *chain = NULL;
|
| + char err[ERR_LEN];
|
| + unsigned long error;
|
| + int n = 0;
|
|
|
| -TCN_IMPLEMENT_CALL(jstring, SSL, getVersion)(TCN_STDARGS, jlong ssl)
|
| -{
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return NULL;
|
| -}
|
| + UNREFERENCED(o);
|
|
|
| -TCN_IMPLEMENT_CALL(jlong, SSL, getTime)(TCN_STDARGS, jlong ssl)
|
| -{
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| + if (cert_bio == NULL) {
|
| + tcn_Throw(e, "No Certificate specified or invalid format");
|
| + goto cleanup;
|
| + }
|
|
|
| -TCN_IMPLEMENT_CALL(jlong, SSL, getTimeout)(TCN_STDARGS, jlong ssl)
|
| -{
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| + chain = sk_X509_new_null();
|
| + while ((cert = PEM_read_bio_X509(cert_bio, NULL, NULL, NULL)) != NULL) {
|
| + if (sk_X509_push(chain, cert) <= 0) {
|
| + tcn_Throw(e, "No Certificate specified or invalid format");
|
| + goto cleanup;
|
| + }
|
| + cert = NULL;
|
| + n++;
|
| + }
|
|
|
| -TCN_IMPLEMENT_CALL(jlong, SSL, setTimeout)(TCN_STDARGS, jlong ssl, jlong seconds)
|
| -{
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - UNREFERENCED(seconds);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| + // ensure that if we have an error its just for EOL.
|
| + if ((error = ERR_peek_error()) > 0) {
|
| + if (!(ERR_GET_LIB(error) == ERR_LIB_PEM
|
| + && ERR_GET_REASON(error) == PEM_R_NO_START_LINE)) {
|
|
|
| -TCN_IMPLEMENT_CALL(void, SSL, setVerify)(TCN_STDARGS, jlong ssl,
|
| - jint level, jint depth)
|
| -{
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| -}
|
| + ERR_error_string_n(ERR_get_error(), err, ERR_LEN);
|
| + tcn_Throw(e, "Invalid format (%s)", err);
|
| + goto cleanup;
|
| + }
|
| + ERR_clear_error();
|
| + }
|
|
|
| -TCN_IMPLEMENT_CALL(void, SSL, setOptions)(TCN_STDARGS, jlong ssl,
|
| - jint opt)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(ssl);
|
| - UNREFERENCED(opt);
|
| - tcn_ThrowException(e, "Not implemented");
|
| -}
|
| + return P2J(chain);
|
|
|
| -TCN_IMPLEMENT_CALL(jint, SSL, getOptions)(TCN_STDARGS, jlong ssl)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return 0;
|
| -}
|
| -TCN_IMPLEMENT_CALL(jobjectArray, SSL, getCiphers)(TCN_STDARGS, jlong ssl)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| +cleanup:
|
| + ERR_clear_error();
|
| + sk_X509_pop_free(chain, X509_free);
|
| + X509_free(cert);
|
| return 0;
|
| }
|
| -TCN_IMPLEMENT_CALL(jboolean, SSL, setCipherSuites)(TCN_STDARGS, jlong ssl,
|
| - jstring ciphers)
|
| -{
|
| - UNREFERENCED_STDARGS;
|
| - UNREFERENCED(ssl);
|
| - UNREFERENCED(ciphers);
|
| - tcn_ThrowException(e, "Not implemented");
|
| - return JNI_FALSE;
|
| -}
|
| -TCN_IMPLEMENT_CALL(jbyteArray, SSL, getSessionId)(TCN_STDARGS, jlong ssl)
|
| -{
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| -}
|
| -TCN_IMPLEMENT_CALL(jint, SSL, getHandshakeCount)(TCN_STDARGS, jlong ssl)
|
| -{
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| -}
|
|
|
| -TCN_IMPLEMENT_CALL(void, SSL, clearError)(TCN_STDARGS)
|
| +TCN_IMPLEMENT_CALL(void, SSL, freeX509Chain)(TCN_STDARGS, jlong x509Chain)
|
| {
|
| + STACK_OF(X509) *chain = J2P(x509Chain, STACK_OF(X509) *);
|
| UNREFERENCED(o);
|
| - tcn_ThrowException(e, "Not implemented");
|
| + sk_X509_pop_free(chain, X509_free);
|
| }
|
|
|
| -TCN_IMPLEMENT_CALL(jint, SSL, renegotiate)(TCN_STDARGS, jlong ssl) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - tcn_ThrowException(e, "Not implemented");
|
| -}
|
| -
|
| -TCN_IMPLEMENT_CALL(void, SSL, setState)(TCN_STDARGS, jlong ssl, jint state) {
|
| - UNREFERENCED(o);
|
| - UNREFERENCED(ssl);
|
| - UNREFERENCED(state);
|
| - tcn_ThrowException(e, "Not implemented");
|
| -}
|
| -/*** End Apple API Additions ***/
|
| -#endif
|
|
|