You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by jf...@apache.org on 2015/06/18 17:55:06 UTC
svn commit: r1686258 - in /tomcat/native/trunk/native: include/ssl_private.h
src/sslcontext.c src/sslutils.c
Author: jfclere
Date: Thu Jun 18 15:55:06 2015
New Revision: 1686258
URL: http://svn.apache.org/r1686258
Log:
Add netty-tcnative methods to sslcontext.c
Modified:
tomcat/native/trunk/native/include/ssl_private.h
tomcat/native/trunk/native/src/sslcontext.c
tomcat/native/trunk/native/src/sslutils.c
Modified: tomcat/native/trunk/native/include/ssl_private.h
URL: http://svn.apache.org/viewvc/tomcat/native/trunk/native/include/ssl_private.h?rev=1686258&r1=1686257&r2=1686258&view=diff
==============================================================================
--- tomcat/native/trunk/native/include/ssl_private.h (original)
+++ tomcat/native/trunk/native/include/ssl_private.h Thu Jun 18 15:55:06 2015
@@ -203,6 +203,9 @@
#endif /* !defined(OPENSSL_NO_TLSEXT) && defined(SSL_set_tlsext_host_name) */
+#define MAX_ALPN_NPN_PROTO_SIZE 65535
+#define SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL 1
+
typedef struct {
/* client can have any number of cert/key pairs */
const char *cert_file;
@@ -259,6 +262,20 @@ struct tcn_ssl_ctxt_t {
*/
char *alpn;
int alpnlen;
+ /* Add from netty-tcnative */
+ /* certificate verifier callback */
+ jobject verifier;
+ jmethodID verifier_method;
+
+ unsigned char *next_proto_data;
+ unsigned int next_proto_len;
+ int next_selector_failure_behavior;
+
+ /* Holds the alpn protocols, each of them prefixed with the len of the protocol */
+ unsigned char *alpn_proto_data;
+ unsigned int alpn_proto_len;
+ int alpn_selector_failure_behavior;
+ /* End add from netty-tcnative */
};
@@ -313,5 +330,9 @@ void SSL_callback_handshake(const
int SSL_CTX_use_certificate_chain(SSL_CTX *, const char *, int);
int SSL_callback_SSL_verify(int, X509_STORE_CTX *);
int SSL_rand_seed(const char *file);
+int SSL_callback_next_protos(SSL *, const unsigned char **, unsigned int *, void *);
+int SSL_callback_select_next_proto(SSL *, unsigned char **, unsigned char *, const unsigned char *, unsigned int,void *);
+int SSL_callback_alpn_select_proto(SSL *, const unsigned char **, unsigned char *, const unsigned char *, unsigned int, void *);
+
#endif /* SSL_PRIVATE_H */
Modified: tomcat/native/trunk/native/src/sslcontext.c
URL: http://svn.apache.org/viewvc/tomcat/native/trunk/native/src/sslcontext.c?rev=1686258&r1=1686257&r2=1686258&view=diff
==============================================================================
--- tomcat/native/trunk/native/src/sslcontext.c (original)
+++ tomcat/native/trunk/native/src/sslcontext.c Thu Jun 18 15:55:06 2015
@@ -26,6 +26,8 @@
#ifdef HAVE_OPENSSL
#include "ssl_private.h"
+static jclass byteArrayClass;
+
static apr_status_t ssl_context_cleanup(void *data)
{
tcn_ssl_ctxt_t *c = (tcn_ssl_ctxt_t *)data;
@@ -55,6 +57,26 @@ static apr_status_t ssl_context_cleanup(
SSL_BIO_close(c->bio_os);
c->bio_os = NULL;
}
+
+ if (c->verifier) {
+ JNIEnv *e;
+ tcn_get_java_env(&e);
+ (*e)->DeleteGlobalRef(e, c->verifier);
+ c->verifier = NULL;
+ }
+ c->verifier_method = NULL;
+
+ if (c->next_proto_data) {
+ free(c->next_proto_data);
+ c->next_proto_data = NULL;
+ }
+ c->next_proto_len = 0;
+
+ if (c->alpn_proto_data) {
+ free(c->alpn_proto_data);
+ c->alpn_proto_data = NULL;
+ }
+ c->alpn_proto_len = 0;
}
return APR_SUCCESS;
}
@@ -67,9 +89,9 @@ static jmethodID sni_java_callback;
*/
int ssl_callback_ServerNameIndication(SSL *ssl, int *al, tcn_ssl_ctxt_t *c)
{
- // TODO: Is it better to cache the JNIEnv* during the call to handshake?
+ /* TODO: Is it better to cache the JNIEnv* during the call to handshake? */
- // Get the JNI environment for this callback
+ /* Get the JNI environment for this callback */
JavaVM *javavm = tcn_get_java_vm();
JNIEnv *env;
const char *servername;
@@ -105,7 +127,9 @@ TCN_IMPLEMENT_CALL(jlong, SSLContext, ma
apr_pool_t *p = J2P(pool, apr_pool_t *);
tcn_ssl_ctxt_t *c = NULL;
SSL_CTX *ctx = NULL;
+ jclass clazz;
+ UNREFERENCED(o);
if (protocol == SSL_PROTOCOL_NONE) {
tcn_Throw(e, "No SSL protocols requested");
goto init_failed;
@@ -211,6 +235,11 @@ TCN_IMPLEMENT_CALL(jlong, SSLContext, ma
#ifdef HAVE_ECC
SSL_CTX_set_options(c->ctx, SSL_OP_SINGLE_ECDH_USE);
#endif
+#ifdef SSL_OP_NO_COMPRESSION
+ /* Disable SSL compression to be safe */
+ SSL_CTX_set_options(c->ctx, SSL_OP_NO_COMPRESSION);
+#endif
+
/** To get back the tomcat wrapper from CTX */
SSL_CTX_set_app_data(c->ctx, (char *)c);
@@ -222,8 +251,17 @@ TCN_IMPLEMENT_CALL(jlong, SSLContext, ma
*/
SSL_CTX_set_options(c->ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
#endif
+#ifdef SSL_MODE_RELEASE_BUFFERS
+ /* Release idle buffers to the SSL_CTX free list */
+ SSL_CTX_set_mode(c->ctx, SSL_MODE_RELEASE_BUFFERS);
+#endif
/* Default session context id and cache size */
SSL_CTX_sess_set_cache_size(c->ctx, SSL_DEFAULT_CACHE_SIZE);
+ /* Session cache is disabled by default */
+ SSL_CTX_set_session_cache_mode(c->ctx, SSL_SESS_CACHE_OFF);
+ /* Longer session timeout */
+ SSL_CTX_set_timeout(c->ctx, 14400);
+
EVP_Digest((const unsigned char *)SSL_DEFAULT_VHOST_NAME,
(unsigned long)((sizeof SSL_DEFAULT_VHOST_NAME) - 1),
&(c->context_id[0]), NULL, EVP_sha1(), NULL);
@@ -258,6 +296,10 @@ TCN_IMPLEMENT_CALL(jlong, SSLContext, ma
ssl_context_cleanup,
apr_pool_cleanup_null);
+ /* Cache the byte[].class for performance reasons */
+ clazz = (*e)->FindClass(e, "[B");
+ byteArrayClass = (jclass) (*e)->NewGlobalRef(e, clazz);
+
return P2J(c);
init_failed:
return 0;
@@ -326,6 +368,16 @@ TCN_IMPLEMENT_CALL(void, SSLContext, set
SSL_CTX_set_options(c->ctx, opt);
}
+TCN_IMPLEMENT_CALL(jint, SSLContext, getOptions)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(ctx != 0);
+
+ return SSL_CTX_get_options(c->ctx);
+}
+
TCN_IMPLEMENT_CALL(void, SSLContext, clearOptions)(TCN_STDARGS, jlong ctx,
jint opt)
{
@@ -502,11 +554,20 @@ TCN_IMPLEMENT_CALL(jboolean, SSLContext,
/*
* Give a warning when no CAs were configured but client authentication
* should take place. This cannot work.
- */
- BIO_printf(c->bio_os,
+ */
+ if (c->bio_os) {
+ BIO_printf(c->bio_os,
+ "[WARN] Oops, you want to request client "
+ "authentication, but no CAs are known for "
+ "verification!?");
+ }
+ else {
+ fprintf(stderr,
"[WARN] Oops, you want to request client "
"authentication, but no CAs are known for "
"verification!?");
+ }
+
}
}
cleanup:
@@ -515,6 +576,98 @@ cleanup:
return rv;
}
+TCN_IMPLEMENT_CALL(void, SSLContext, setTmpDH)(TCN_STDARGS, jlong ctx,
+ jstring file)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ BIO *bio = NULL;
+ DH *dh = NULL;
+ TCN_ALLOC_CSTRING(file);
+ UNREFERENCED(o);
+ TCN_ASSERT(ctx != 0);
+ TCN_ASSERT(file);
+
+ if (!J2S(file)) {
+ tcn_Throw(e, "Error while configuring DH: no dh param file given");
+ return;
+ }
+
+ bio = BIO_new_file(J2S(file), "r");
+ if (!bio) {
+ char err[256];
+ ERR_error_string(ERR_get_error(), err);
+ tcn_Throw(e, "Error while configuring DH using %s: %s", J2S(file), err);
+ TCN_FREE_CSTRING(file);
+ return;
+ }
+
+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ if (!dh) {
+ char err[256];
+ ERR_error_string(ERR_get_error(), err);
+ tcn_Throw(e, "Error while configuring DH: no DH parameter found in %s (%s)", J2S(file), err);
+ TCN_FREE_CSTRING(file);
+ return;
+ }
+
+ if (1 != SSL_CTX_set_tmp_dh(c->ctx, dh)) {
+ char err[256];
+ DH_free(dh);
+ ERR_error_string(ERR_get_error(), err);
+ tcn_Throw(e, "Error while configuring DH with file %s: %s", J2S(file), err);
+ TCN_FREE_CSTRING(file);
+ return;
+ }
+
+ DH_free(dh);
+ TCN_FREE_CSTRING(file);
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setTmpECDHByCurveName)(TCN_STDARGS, jlong ctx,
+ jstring curveName)
+{
+#ifdef HAVE_ECC
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ int i;
+ EC_KEY *ecdh;
+ TCN_ALLOC_CSTRING(curveName);
+ UNREFERENCED(o);
+ TCN_ASSERT(ctx != 0);
+ TCN_ASSERT(curveName);
+
+ /* First try to get curve by name */
+ i = OBJ_sn2nid(J2S(curveName));
+ if (!i) {
+ tcn_Throw(e, "Can't configure elliptic curve: unknown curve name %s", J2S(curveName));
+ TCN_FREE_CSTRING(curveName);
+ return;
+ }
+
+ ecdh = EC_KEY_new_by_curve_name(i);
+ if (!ecdh) {
+ tcn_Throw(e, "Can't configure elliptic curve: unknown curve name %s", J2S(curveName));
+ TCN_FREE_CSTRING(curveName);
+ return;
+ }
+
+ /* Setting found curve to context */
+ if (1 != SSL_CTX_set_tmp_ecdh(c->ctx, ecdh)) {
+ char err[256];
+ EC_KEY_free(ecdh);
+ ERR_error_string(ERR_get_error(), err);
+ tcn_Throw(e, "Error while configuring elliptic curve %s: %s", J2S(curveName), err);
+ TCN_FREE_CSTRING(curveName);
+ return;
+ }
+ EC_KEY_free(ecdh);
+ TCN_FREE_CSTRING(curveName);
+#else
+ tcn_Throw(e, "Cant't configure elliptic curve: unsupported by this OpenSSL version");
+ return;
+#endif
+}
+
TCN_IMPLEMENT_CALL(void, SSLContext, setShutdownType)(TCN_STDARGS, jlong ctx,
jint type)
{
@@ -940,13 +1093,497 @@ TCN_IMPLEMENT_CALL(jint, SSLContext, set
if (sslctx->mode == SSL_MODE_SERVER) {
SSL_CTX_set_alpn_select_cb(sslctx->ctx, cb_server_alpn, sslctx);
} else {
- // TODO: Implement client side call-back
- // SSL_CTX_set_next_proto_select_cb(sslctx->ctx, cb_request_alpn, sslctx);
+ /*
+ * TODO: Implement client side call-back
+ * SSL_CTX_set_next_proto_select_cb(sslctx->ctx, cb_request_alpn, sslctx);
+ */
return APR_ENOTIMPL;
}
return 0;
}
+/* Start of netty-tc-native add */
+
+/* Convert protos to wire format */
+static int initProtocols(JNIEnv *e, const tcn_ssl_ctxt_t *c, unsigned char **proto_data,
+ unsigned int *proto_len, jobjectArray protos) {
+ int i;
+ unsigned char *p_data;
+ /*
+ * We start with allocate 128 bytes which should be good enough for most use-cases while still be pretty low.
+ * We will call realloc to increate this if needed.
+ */
+ size_t p_data_size = 128;
+ size_t p_data_len = 0;
+ jstring proto_string;
+ const char *proto_chars;
+ size_t proto_chars_len;
+ int cnt;
+
+ if (protos == NULL) {
+ // Guard against NULL protos.
+ return -1;
+ }
+
+ cnt = (*e)->GetArrayLength(e, protos);
+
+ if (cnt == 0) {
+ // if cnt is 0 we not need to continue and can just fail fast.
+ return -1;
+ }
+
+ p_data = (unsigned char *) malloc(p_data_size);
+ if (p_data == NULL) {
+ // Not enough memory?
+ return -1;
+ }
+
+ for (i = 0; i < cnt; ++i) {
+ proto_string = (jstring) (*e)->GetObjectArrayElement(e, protos, i);
+ proto_chars = (*e)->GetStringUTFChars(e, proto_string, 0);
+
+ proto_chars_len = strlen(proto_chars);
+ if (proto_chars_len > 0 && proto_chars_len <= MAX_ALPN_NPN_PROTO_SIZE) {
+ // We need to add +1 as each protocol is prefixed by it's length (unsigned char).
+ // For all except of the last one we already have the extra space as everything is
+ // delimited by ','.
+ p_data_len += 1 + proto_chars_len;
+ if (p_data_len > p_data_size) {
+ // double size
+ p_data_size <<= 1;
+ p_data = realloc(p_data, p_data_size);
+ if (p_data == NULL) {
+ // Not enough memory?
+ (*e)->ReleaseStringUTFChars(e, proto_string, proto_chars);
+ break;
+ }
+ }
+ // Write the length of the protocol and then increment before memcpy the protocol itself.
+ *p_data = proto_chars_len;
+ ++p_data;
+ memcpy(p_data, proto_chars, proto_chars_len);
+ p_data += proto_chars_len;
+ }
+
+ // Release the string to prevent memory leaks
+ (*e)->ReleaseStringUTFChars(e, proto_string, proto_chars);
+ }
+
+ if (p_data == NULL) {
+ // Something went wrong so update the proto_len and return -1
+ *proto_len = 0;
+ return -1;
+ } else {
+ if (*proto_data != NULL) {
+ // Free old data
+ free(*proto_data);
+ }
+ // Decrement pointer again as we incremented it while creating the protocols in wire format.
+ p_data -= p_data_len;
+ *proto_data = p_data;
+ *proto_len = p_data_len;
+ return 0;
+ }
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setNpnProtos)(TCN_STDARGS, jlong ctx, jobjectArray next_protos,
+ jint selectorFailureBehavior)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+
+ TCN_ASSERT(ctx != 0);
+ UNREFERENCED(o);
+
+ if (initProtocols(e, c, &c->next_proto_data, &c->next_proto_len, next_protos) == 0) {
+ c->next_selector_failure_behavior = selectorFailureBehavior;
+
+ // depending on if it's client mode or not we need to call different functions.
+ if (c->mode == SSL_MODE_CLIENT) {
+ SSL_CTX_set_next_proto_select_cb(c->ctx, SSL_callback_select_next_proto, (void *)c);
+ } else {
+ SSL_CTX_set_next_protos_advertised_cb(c->ctx, SSL_callback_next_protos, (void *)c);
+ }
+ }
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setAlpnProtos)(TCN_STDARGS, jlong ctx, jobjectArray alpn_protos,
+ jint selectorFailureBehavior)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+
+ TCN_ASSERT(ctx != 0);
+ UNREFERENCED(o);
+
+ if (initProtocols(e, c, &c->alpn_proto_data, &c->alpn_proto_len, alpn_protos) == 0) {
+ c->alpn_selector_failure_behavior = selectorFailureBehavior;
+
+ // depending on if it's client mode or not we need to call different functions.
+ if (c->mode == SSL_MODE_CLIENT) {
+ SSL_CTX_set_alpn_protos(c->ctx, c->alpn_proto_data, c->alpn_proto_len);
+ } else {
+ SSL_CTX_set_alpn_select_cb(c->ctx, SSL_callback_alpn_select_proto, (void *) c);
+
+ }
+ }
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, setSessionCacheMode)(TCN_STDARGS, jlong ctx, jlong mode)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ return SSL_CTX_set_session_cache_mode(c->ctx, mode);
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, getSessionCacheMode)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ return SSL_CTX_get_session_cache_mode(c->ctx);
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, setSessionCacheTimeout)(TCN_STDARGS, jlong ctx, jlong timeout)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = SSL_CTX_set_timeout(c->ctx, timeout);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, getSessionCacheTimeout)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ return SSL_CTX_get_timeout(c->ctx);
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, setSessionCacheSize)(TCN_STDARGS, jlong ctx, jlong size)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = 0;
+
+ // Also allow size of 0 which is unlimited
+ if (size >= 0) {
+ SSL_CTX_set_session_cache_mode(c->ctx, SSL_SESS_CACHE_SERVER);
+ rv = SSL_CTX_sess_set_cache_size(c->ctx, size);
+ }
+
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, getSessionCacheSize)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ return SSL_CTX_sess_get_cache_size(c->ctx);
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, sessionNumber)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = SSL_CTX_sess_number(c->ctx);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, sessionConnect)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = SSL_CTX_sess_connect(c->ctx);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, sessionConnectGood)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = SSL_CTX_sess_connect_good(c->ctx);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, sessionConnectRenegotiate)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = SSL_CTX_sess_connect_renegotiate(c->ctx);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, sessionAccept)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = SSL_CTX_sess_accept(c->ctx);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, sessionAcceptGood)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = SSL_CTX_sess_accept_good(c->ctx);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, sessionAcceptRenegotiate)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = SSL_CTX_sess_accept_renegotiate(c->ctx);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, sessionHits)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = SSL_CTX_sess_hits(c->ctx);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, sessionCbHits)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = SSL_CTX_sess_cb_hits(c->ctx);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, sessionMisses)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = SSL_CTX_sess_misses(c->ctx);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, sessionTimeouts)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = SSL_CTX_sess_timeouts(c->ctx);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSLContext, sessionCacheFull)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jlong rv = SSL_CTX_sess_cache_full(c->ctx);
+ return rv;
+}
+
+#define TICKET_KEYS_SIZE 48
+TCN_IMPLEMENT_CALL(void, SSLContext, setSessionTicketKeys)(TCN_STDARGS, jlong ctx, jbyteArray keys)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jbyte* b;
+
+ if ((*e)->GetArrayLength(e, keys) != TICKET_KEYS_SIZE) {
+ if (c->bio_os) {
+ BIO_printf(c->bio_os, "[ERROR] Session ticket keys provided were wrong size.");
+ }
+ else {
+ fprintf(stderr, "[ERROR] Session ticket keys provided were wrong size.");
+ }
+ exit(1);
+ }
+
+ b = (*e)->GetByteArrayElements(e, keys, NULL);
+ SSL_CTX_set_tlsext_ticket_keys(c->ctx, b, TICKET_KEYS_SIZE);
+ (*e)->ReleaseByteArrayElements(e, keys, b, 0);
+}
+
+
+/*
+ * Adapted from OpenSSL:
+ * http://osxr.org/openssl/source/ssl/ssl_locl.h#0291
+ */
+/* Bits for algorithm_mkey (key exchange algorithm) */
+#define SSL_kRSA 0x00000001L /* RSA key exchange */
+#define SSL_kDHr 0x00000002L /* DH cert, RSA CA cert */ /* no such ciphersuites supported! */
+#define SSL_kDHd 0x00000004L /* DH cert, DSA CA cert */ /* no such ciphersuite supported! */
+#define SSL_kEDH 0x00000008L /* tmp DH key no DH cert */
+#define SSL_kKRB5 0x00000010L /* Kerberos5 key exchange */
+#define SSL_kECDHr 0x00000020L /* ECDH cert, RSA CA cert */
+#define SSL_kECDHe 0x00000040L /* ECDH cert, ECDSA CA cert */
+#define SSL_kEECDH 0x00000080L /* ephemeral ECDH */
+#define SSL_kPSK 0x00000100L /* PSK */
+#define SSL_kGOST 0x00000200L /* GOST key exchange */
+#define SSL_kSRP 0x00000400L /* SRP */
+
+/* Bits for algorithm_auth (server authentication) */
+#define SSL_aRSA 0x00000001L /* RSA auth */
+#define SSL_aDSS 0x00000002L /* DSS auth */
+#define SSL_aNULL 0x00000004L /* no auth (i.e. use ADH or AECDH) */
+#define SSL_aDH 0x00000008L /* Fixed DH auth (kDHd or kDHr) */ /* no such ciphersuites supported! */
+#define SSL_aECDH 0x00000010L /* Fixed ECDH auth (kECDHe or kECDHr) */
+#define SSL_aKRB5 0x00000020L /* KRB5 auth */
+#define SSL_aECDSA 0x00000040L /* ECDSA auth*/
+#define SSL_aPSK 0x00000080L /* PSK auth */
+#define SSL_aGOST94 0x00000100L /* GOST R 34.10-94 signature auth */
+#define SSL_aGOST01 0x00000200L /* GOST R 34.10-2001 signature auth */
+
+/* OpenSSL end */
+
+/*
+ * Adapted from Android:
+ * https://android.googlesource.com/platform/external/openssl/+/master/patches/0003-jsse.patch
+ */
+const char* SSL_CIPHER_authentication_method(const SSL_CIPHER* cipher){
+ switch (cipher->algorithm_mkey)
+ {
+ case SSL_kRSA:
+ return SSL_TXT_RSA;
+ case SSL_kDHr:
+ return SSL_TXT_DH "_" SSL_TXT_RSA;
+ case SSL_kDHd:
+ return SSL_TXT_DH "_" SSL_TXT_DSS;
+ case SSL_kEDH:
+ switch (cipher->algorithm_auth)
+ {
+ case SSL_aDSS:
+ return "DHE_" SSL_TXT_DSS;
+ case SSL_aRSA:
+ return "DHE_" SSL_TXT_RSA;
+ case SSL_aNULL:
+ return SSL_TXT_DH "_anon";
+ default:
+ return "UNKNOWN";
+ }
+ case SSL_kKRB5:
+ return SSL_TXT_KRB5;
+ case SSL_kECDHr:
+ return SSL_TXT_ECDH "_" SSL_TXT_RSA;
+ case SSL_kECDHe:
+ return SSL_TXT_ECDH "_" SSL_TXT_ECDSA;
+ case SSL_kEECDH:
+ switch (cipher->algorithm_auth)
+ {
+ case SSL_aECDSA:
+ return "ECDHE_" SSL_TXT_ECDSA;
+ case SSL_aRSA:
+ return "ECDHE_" SSL_TXT_RSA;
+ case SSL_aNULL:
+ return SSL_TXT_ECDH "_anon";
+ default:
+ return "UNKNOWN";
+ }
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static const char* SSL_authentication_method(const SSL* ssl) {
+{
+ switch (ssl->version)
+ {
+ case SSL2_VERSION:
+ return SSL_TXT_RSA;
+ default:
+ return SSL_CIPHER_authentication_method(ssl->s3->tmp.new_cipher);
+ }
+ }
+}
+/* Android end */
+
+static int SSL_cert_verify(X509_STORE_CTX *ctx, void *arg) {
+ /* Get Apache context back through OpenSSL context */
+ SSL *ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+ tcn_ssl_ctxt_t *c = SSL_get_app_data2(ssl);
+
+
+ // Get a stack of all certs in the chain
+ STACK_OF(X509) *sk = ctx->untrusted;
+
+ int len = sk_X509_num(sk);
+ unsigned i;
+ X509 *cert;
+ int length;
+ unsigned char *buf;
+ JNIEnv *e;
+ jbyteArray array;
+ jbyteArray bArray;
+ const char *authMethod;
+ jstring authMethodString;
+ jboolean result;
+ int r;
+ tcn_get_java_env(&e);
+
+ // Create the byte[][]Â array that holds all the certs
+ array = (*e)->NewObjectArray(e, len, byteArrayClass, NULL);
+
+ for(i = 0; i < len; i++) {
+ cert = (X509*) sk_X509_value(sk, i);
+
+ buf = NULL;
+ length = i2d_X509(cert, &buf);
+ if (length < 0) {
+ // In case of error just return an empty byte[][]
+ array = (*e)->NewObjectArray(e, 0, byteArrayClass, NULL);
+ // We need to delete the local references so we not leak memory as this method is called via callback.
+ OPENSSL_free(buf);
+ break;
+ }
+ bArray = (*e)->NewByteArray(e, length);
+ (*e)->SetByteArrayRegion(e, bArray, 0, length, (jbyte*) buf);
+ (*e)->SetObjectArrayElement(e, array, i, bArray);
+
+ // Delete the local reference as we not know how long the chain is and local references are otherwise
+ // only freed once jni method returns.
+ (*e)->DeleteLocalRef(e, bArray);
+ OPENSSL_free(buf);
+ }
+
+ authMethod = SSL_authentication_method(ssl);
+ authMethodString = (*e)->NewStringUTF(e, authMethod);
+
+ result = (*e)->CallBooleanMethod(e, c->verifier, c->verifier_method, P2J(ssl), array,
+ authMethodString);
+
+ r = result == JNI_TRUE ? 1 : 0;
+
+ // We need to delete the local references so we not leak memory as this method is called via callback.
+ (*e)->DeleteLocalRef(e, authMethodString);
+ (*e)->DeleteLocalRef(e, array);
+ return r;
+}
+
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setCertVerifyCallback)(TCN_STDARGS, jlong ctx, jobject verifier)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+
+ UNREFERENCED(o);
+ TCN_ASSERT(ctx != 0);
+
+ if (verifier == NULL) {
+ SSL_CTX_set_cert_verify_callback(c->ctx, NULL, NULL);
+ } else {
+ jclass verifier_class = (*e)->GetObjectClass(e, verifier);
+ jmethodID method = (*e)->GetMethodID(e, verifier_class, "verify", "(J[[BLjava/lang/String;)Z");
+
+ if (method == NULL) {
+ return;
+ }
+ // Delete the reference to the previous specified verifier if needed.
+ if (c->verifier != NULL) {
+ (*e)->DeleteLocalRef(e, c->verifier);
+ }
+ c->verifier = (*e)->NewGlobalRef(e, verifier);
+ c->verifier_method = method;
+
+ SSL_CTX_set_cert_verify_callback(c->ctx, SSL_cert_verify, NULL);
+ }
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSLContext, setSessionIdContext)(TCN_STDARGS, jlong ctx, jbyteArray sidCtx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ int len = (*e)->GetArrayLength(e, sidCtx);
+ unsigned char *buf;
+ int res;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(ctx != 0);
+
+ buf = malloc(len);
+
+ (*e)->GetByteArrayRegion(e, sidCtx, 0, len, (jbyte*) buf);
+
+ res = SSL_CTX_set_session_id_context(c->ctx, buf, len);
+ free(buf);
+
+ if (res == 1) {
+ return JNI_TRUE;
+ }
+ return JNI_FALSE;
+}
+
+/* End of netty-tc-native add */
#else
/* OpenSSL is not supported.
* Create empty stubs.
Modified: tomcat/native/trunk/native/src/sslutils.c
URL: http://svn.apache.org/viewvc/tomcat/native/trunk/native/src/sslutils.c?rev=1686258&r1=1686257&r2=1686258&view=diff
==============================================================================
--- tomcat/native/trunk/native/src/sslutils.c (original)
+++ tomcat/native/trunk/native/src/sslutils.c Thu Jun 18 15:55:06 2015
@@ -562,6 +562,87 @@ void SSL_callback_handshake(const SSL *s
}
+int SSL_callback_next_protos(SSL *ssl, const unsigned char **data,
+ unsigned int *len, void *arg)
+{
+ tcn_ssl_ctxt_t *ssl_ctxt = arg;
+
+ *data = ssl_ctxt->next_proto_data;
+ *len = ssl_ctxt->next_proto_len;
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+/* The code here is inspired by nghttp2
+ *
+ * See https://github.com/tatsuhiro-t/nghttp2/blob/ae0100a9abfcf3149b8d9e62aae216e946b517fb/src/shrpx_ssl.cc#L244 */
+int select_next_proto(SSL *ssl, const unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen, unsigned char *supported_protos,
+ unsigned int supported_protos_len, int failure_behavior) {
+
+ unsigned int i = 0;
+ unsigned char target_proto_len;
+ const unsigned char *p;
+ const unsigned char *end;
+ const unsigned char *proto;
+ unsigned char proto_len;
+
+ while (i < supported_protos_len) {
+ target_proto_len = *supported_protos;
+ ++supported_protos;
+
+ p = in;
+ end = in + inlen;
+
+ while (p < end) {
+ proto_len = *p;
+ proto = ++p;
+
+ if (proto + proto_len <= end && target_proto_len == proto_len &&
+ memcmp(supported_protos, proto, proto_len) == 0) {
+
+ // We found a match, so set the output and return with OK!
+ *out = proto;
+ *outlen = proto_len;
+
+ return SSL_TLSEXT_ERR_OK;
+ }
+ // Move on to the next protocol.
+ p += proto_len;
+ }
+
+ // increment len and pointers.
+ i += target_proto_len;
+ supported_protos += target_proto_len;
+ }
+
+ if (failure_behavior == SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL) {
+ // There were no match but we just select our last protocol and hope the other peer support it.
+ //
+ // decrement the pointer again so the pointer points to the start of the protocol.
+ p -= proto_len;
+ *out = p;
+ *outlen = proto_len;
+ return SSL_TLSEXT_ERR_OK;
+ }
+ // TODO: OpenSSL currently not support to fail with fatal error. Once this changes we can also support it here.
+ // Issue https://github.com/openssl/openssl/issues/188 has been created for this.
+ // Nothing matched so not select anything and just accept.
+ return SSL_TLSEXT_ERR_NOACK;
+}
+
+int SSL_callback_select_next_proto(SSL *ssl, unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen,
+ void *arg) {
+ tcn_ssl_ctxt_t *ssl_ctxt = arg;
+ return select_next_proto(ssl, (const unsigned char **) out, outlen, in, inlen, ssl_ctxt->next_proto_data, ssl_ctxt->next_proto_len, ssl_ctxt->next_selector_failure_behavior);
+}
+
+int SSL_callback_alpn_select_proto(SSL* ssl, const unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen, void *arg) {
+ tcn_ssl_ctxt_t *ssl_ctxt = arg;
+ return select_next_proto(ssl, out, outlen, in, inlen, ssl_ctxt->alpn_proto_data, ssl_ctxt->alpn_proto_len, ssl_ctxt->alpn_selector_failure_behavior);
+}
#ifdef HAVE_OCSP_STAPLING
/* Function that is used to do the OCSP verification */
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org