Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(416)

Unified Diff: c/ssl.c

Issue 2842333002: Updated netty-tcnative to version 2.0.0.Final (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « c/shm.c ('k') | c/ssl_private.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « c/shm.c ('k') | c/ssl_private.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698