Skip to content

Commit

Permalink
Add support for TLSv1.3 when compiled against openssl 1.1.1 (netty#389)
Browse files Browse the repository at this point in the history
Motivation:

OpenSSL 1.1.1 was released which supports TLSv1.3 and it is the now the current LTS release. We should be able to compile against it and also support TLSv1.3.

Modifications:

- Add some new native methods to allow to set TLSv1.3 ciphersuites
- Depending on if TLSv1.3 is supported or not set some flags

Result:

Be able to compile against OpenSSL 1.1.1 and make use of TLSv1.3. Fixes netty#345 and netty#256
  • Loading branch information
normanmaurer committed Sep 20, 2018
1 parent 622a7f7 commit a811c77
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 28 deletions.
5 changes: 5 additions & 0 deletions openssl-dynamic/src/main/c/native_constants.c
Expand Up @@ -42,6 +42,10 @@ TCN_IMPLEMENT_CALL(jint, NativeStaticallyReferencedJniMethods, sslOpNoTLSv12)(TC
return SSL_OP_NO_TLSv1_2;
}

TCN_IMPLEMENT_CALL(jint, NativeStaticallyReferencedJniMethods, sslOpNoTLSv13)(TCN_STDARGS) {
return SSL_OP_NO_TLSv1_3;
}

TCN_IMPLEMENT_CALL(jint, NativeStaticallyReferencedJniMethods, sslOpNoTicket)(TCN_STDARGS) {
return SSL_OP_NO_TICKET;
}
Expand Down Expand Up @@ -484,6 +488,7 @@ static const JNINativeMethod method_table[] = {
{ TCN_METHOD_TABLE_ENTRY(sslOpNoTLSv1, ()I, NativeStaticallyReferencedJniMethods) },
{ TCN_METHOD_TABLE_ENTRY(sslOpNoTLSv11, ()I, NativeStaticallyReferencedJniMethods) },
{ TCN_METHOD_TABLE_ENTRY(sslOpNoTLSv12, ()I, NativeStaticallyReferencedJniMethods) },
{ TCN_METHOD_TABLE_ENTRY(sslOpNoTLSv13, ()I, NativeStaticallyReferencedJniMethods) },
{ TCN_METHOD_TABLE_ENTRY(sslOpNoTicket, ()I, NativeStaticallyReferencedJniMethods) },
{ TCN_METHOD_TABLE_ENTRY(sslOpNoCompression, ()I, NativeStaticallyReferencedJniMethods) },
{ TCN_METHOD_TABLE_ENTRY(sslSessCacheOff, ()I, NativeStaticallyReferencedJniMethods) },
Expand Down
30 changes: 22 additions & 8 deletions openssl-dynamic/src/main/c/ssl.c
Expand Up @@ -1559,27 +1559,41 @@ TCN_IMPLEMENT_CALL(jobjectArray, SSL, getCiphers)(TCN_STDARGS, jlong ssl)
}

TCN_IMPLEMENT_CALL(jboolean, SSL, setCipherSuites)(TCN_STDARGS, jlong ssl,
jstring ciphers)
jstring ciphers, jboolean tlsv13)
{
jboolean rv = JNI_TRUE;
TCN_ALLOC_CSTRING(ciphers);
SSL *ssl_ = J2P(ssl, SSL *);

TCN_CHECK_NULL(ssl_, ssl, JNI_FALSE);

UNREFERENCED(o);
#ifdef OPENSSL_NO_TLS1_3
if (tlsv13 == JNI_TRUE) {
tcn_Throw(e, "TLSv1.3 not supported");
return JNI_FALSE;
}
#endif

TCN_ALLOC_CSTRING(ciphers);
UNREFERENCED(o);
if (!J2S(ciphers)) {
return JNI_FALSE;
}

if (!SSL_set_cipher_list(ssl_, J2S(ciphers))) {
char err[ERR_LEN];
#ifdef OPENSSL_NO_TLS1_3
rv = SSL_set_cipher_list(ssl_, J2S(ciphers)) == 0 ? JNI_FALSE : JNI_TRUE;
#else
if (tlsv13 == JNI_TRUE) {
rv = SSL_set_ciphersuites(ssl_, J2S(ciphers)) == 0 ? JNI_FALSE : JNI_TRUE;
} else {
rv = SSL_set_cipher_list(ssl_, J2S(ciphers)) == 0 ? JNI_FALSE : JNI_TRUE;
}
#endif

if (rv == JNI_FALSE) {
char err[256];
ERR_error_string(ERR_get_error(), err);
tcn_Throw(e, "Unable to configure permitted SSL ciphers (%s)", err);
rv = JNI_FALSE;
}

TCN_FREE_CSTRING(ciphers);
return rv;
}
Expand Down Expand Up @@ -2307,7 +2321,7 @@ static const JNINativeMethod method_table[] = {
{ TCN_METHOD_TABLE_ENTRY(getMode, (J)I, SSL) },
{ TCN_METHOD_TABLE_ENTRY(getMaxWrapOverhead, (J)I, SSL) },
{ TCN_METHOD_TABLE_ENTRY(getCiphers, (J)[Ljava/lang/String;, SSL) },
{ TCN_METHOD_TABLE_ENTRY(setCipherSuites, (JLjava/lang/String;)Z, SSL) },
{ TCN_METHOD_TABLE_ENTRY(setCipherSuites, (JLjava/lang/String;Z)Z, SSL) },
{ TCN_METHOD_TABLE_ENTRY(getSessionId, (J)[B, SSL) },
{ TCN_METHOD_TABLE_ENTRY(getHandshakeCount, (J)I, SSL) },
{ TCN_METHOD_TABLE_ENTRY(clearError, ()V, SSL) },
Expand Down
16 changes: 16 additions & 0 deletions openssl-dynamic/src/main/c/ssl_private.h
Expand Up @@ -131,6 +131,22 @@ extern const char* TCN_UNKNOWN_AUTH_METHOD;
#define TLS1_3_VERSION 0x0304
#endif

#ifndef SSL_OP_NO_TLSv1_3
// TLSV1_3 is not really supported by the underlying OPENSSL version
#ifndef OPENSSL_NO_TLS1_3
#define OPENSSL_NO_TLS1_3
#endif // OPENSSL_NO_TLS1_3

#define SSL_OP_NO_TLSv1_3 0x20000000U
#endif // SSL_OP_NO_TLSv1_3

// BoringSSL does not support TLSv1.3 for now
#ifdef OPENSSL_IS_BORINGSSL
#ifndef OPENSSL_NO_TLS1_3
#define OPENSSL_NO_TLS1_3
#endif // OPENSSL_NO_TLS1_3
#endif // OPENSSL_IS_BORINGSSL

/* OpenSSL 1.0.2 compatibility */
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
#define TLS_method SSLv23_method
Expand Down
36 changes: 23 additions & 13 deletions openssl-dynamic/src/main/c/sslcontext.c
Expand Up @@ -422,24 +422,40 @@ TCN_IMPLEMENT_CALL(void, SSLContext, clearOptions)(TCN_STDARGS, jlong ctx,
}

TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCipherSuite)(TCN_STDARGS, jlong ctx,
jstring ciphers)
jstring ciphers, jboolean tlsv13)
{
tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
jboolean rv = JNI_TRUE;

TCN_CHECK_NULL(c, ctx, JNI_FALSE);

TCN_ALLOC_CSTRING(ciphers);
#ifdef OPENSSL_NO_TLS1_3
if (tlsv13 == JNI_TRUE) {
tcn_Throw(e, "TLSv1.3 not supported");
return JNI_FALSE;
}
#endif

TCN_ALLOC_CSTRING(ciphers);
UNREFERENCED(o);
if (!J2S(ciphers))
if (!J2S(ciphers)) {
return JNI_FALSE;
}

#ifdef OPENSSL_NO_TLS1_3
rv = SSL_CTX_set_cipher_list(c->ctx, J2S(ciphers)) == 0 ? JNI_FALSE : JNI_TRUE;
#else
if (tlsv13 == JNI_TRUE) {
rv = SSL_CTX_set_ciphersuites(c->ctx, J2S(ciphers)) == 0 ? JNI_FALSE : JNI_TRUE;
} else {
rv = SSL_CTX_set_cipher_list(c->ctx, J2S(ciphers)) == 0 ? JNI_FALSE : JNI_TRUE;
}
#endif

if (!SSL_CTX_set_cipher_list(c->ctx, J2S(ciphers))) {
if (rv == JNI_FALSE) {
char err[256];
ERR_error_string(ERR_get_error(), err);
tcn_Throw(e, "Unable to configure permitted SSL ciphers (%s)", err);
rv = JNI_FALSE;
}
TCN_FREE_CSTRING(ciphers);
return rv;
Expand Down Expand Up @@ -1434,13 +1450,12 @@ TCN_IMPLEMENT_CALL(void, SSLContext, setCertVerifyCallback)(TCN_STDARGS, jlong c
}
}


static jbyteArray keyTypes(JNIEnv* e, SSL* ssl) {
jbyte* ctype_bytes;
jbyteArray types;
int ctype_num = tcn_SSL_get0_certificate_types(ssl, (const uint8_t **) &ctype_bytes);
if (ctype_num <= 0) {
// Use no certificate
// No idea what we should use... Let the caller handle it.
return NULL;
}
types = (*e)->NewByteArray(e, ctype_num);
Expand All @@ -1451,7 +1466,6 @@ static jbyteArray keyTypes(JNIEnv* e, SSL* ssl) {
return types;
}


/**
* Returns an array containing all the X500 principal's bytes.
*
Expand Down Expand Up @@ -1527,10 +1541,6 @@ static int cert_requested(SSL* ssl, X509** x509Out, EVP_PKEY** pkeyOut) {
tcn_get_java_env(&e);

types = keyTypes(e, ssl);
if (types == NULL) {
return 0;
}

issuers = principalBytes(e, SSL_get_client_CA_list(ssl));

// Execute the java callback
Expand Down Expand Up @@ -1870,7 +1880,7 @@ static const JNINativeMethod fixed_method_table[] = {
{ TCN_METHOD_TABLE_ENTRY(setOptions, (JI)V, SSLContext) },
{ TCN_METHOD_TABLE_ENTRY(getOptions, (J)I, SSLContext) },
{ TCN_METHOD_TABLE_ENTRY(clearOptions, (JI)V, SSLContext) },
{ TCN_METHOD_TABLE_ENTRY(setCipherSuite, (JLjava/lang/String;)Z, SSLContext) },
{ TCN_METHOD_TABLE_ENTRY(setCipherSuite, (JLjava/lang/String;Z)Z, SSLContext) },
{ TCN_METHOD_TABLE_ENTRY(setCertificateChainFile, (JLjava/lang/String;Z)Z, SSLContext) },
{ TCN_METHOD_TABLE_ENTRY(setCertificateChainBio, (JJZ)Z, SSLContext) },
{ TCN_METHOD_TABLE_ENTRY(setCACertificateBio, (JJ)Z, SSLContext) },
Expand Down
6 changes: 6 additions & 0 deletions openssl-dynamic/src/main/c/sslutils.c
Expand Up @@ -106,6 +106,12 @@ const char* tcn_SSL_cipher_authentication_method(const SSL_CIPHER* cipher){
default:
return TCN_UNKNOWN_AUTH_METHOD;
}
#ifndef OPENSSL_NO_TLS1_3
case NID_kx_any:
// Let us just pick one as we could use whatever we want.
// See https://www.openssl.org/docs/man1.1.1/man3/SSL_CIPHER_get_kx_nid.html
return "ECDHE_" SSL_TXT_RSA;
#endif
default:
return TCN_UNKNOWN_AUTH_METHOD;
}
Expand Down
Expand Up @@ -40,6 +40,7 @@ private NativeStaticallyReferencedJniMethods() {
static native int sslOpNoTLSv1();
static native int sslOpNoTLSv11();
static native int sslOpNoTLSv12();
static native int sslOpNoTLSv13();
static native int sslOpNoTicket();

/**
Expand Down
31 changes: 28 additions & 3 deletions openssl-dynamic/src/main/java/io/netty/internal/tcnative/SSL.java
Expand Up @@ -50,9 +50,10 @@ private SSL() { }
public static final int SSL_PROTOCOL_TLSV1 = (1<<2);
public static final int SSL_PROTOCOL_TLSV1_1 = (1<<3);
public static final int SSL_PROTOCOL_TLSV1_2 = (1<<4);
public static final int SSL_PROTOCOL_TLSV1_3 = (1<<5);

/** TLS_*method according to <a href="https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_new.html">SSL_CTX_new</a> */
public static final int SSL_PROTOCOL_TLS = (SSL_PROTOCOL_SSLV3 | SSL_PROTOCOL_TLSV1 | SSL_PROTOCOL_TLSV1_1 | SSL_PROTOCOL_TLSV1_2);
public static final int SSL_PROTOCOL_TLS = (SSL_PROTOCOL_SSLV3 | SSL_PROTOCOL_TLSV1 | SSL_PROTOCOL_TLSV1_1 | SSL_PROTOCOL_TLSV1_2 | SSL_PROTOCOL_TLSV1_3);
public static final int SSL_PROTOCOL_ALL = (SSL_PROTOCOL_SSLV2 | SSL_PROTOCOL_TLS);

/*
Expand All @@ -69,6 +70,7 @@ private SSL() { }
public static final int SSL_OP_NO_TLSv1 = sslOpNoTLSv1();
public static final int SSL_OP_NO_TLSv1_1 = sslOpNoTLSv11();
public static final int SSL_OP_NO_TLSv1_2 = sslOpNoTLSv12();
public static final int SSL_OP_NO_TLSv1_3 = sslOpNoTLSv13();
public static final int SSL_OP_NO_TICKET = sslOpNoTicket();

public static final int SSL_OP_NO_COMPRESSION = sslOpNoCompression();
Expand Down Expand Up @@ -500,10 +502,33 @@ private SSL() { }
* @param ciphers an SSL cipher specification
* @return {@code true} if successful
* @throws Exception if an error happened
* @deprecated Use {@link #setCipherSuites(long, String, boolean)}
*/
public static native boolean setCipherSuites(long ssl, String ciphers)
throws Exception;
@Deprecated
public static boolean setCipherSuites(long ssl, String ciphers)
throws Exception {
return setCipherSuites(ssl, ciphers, false);
}

/**
* Returns the cipher suites available for negotiation in SSL handshake.
* <p>
* This complex directive uses a colon-separated cipher-spec string consisting
* of OpenSSL cipher specifications to configure the Cipher Suite the client
* is permitted to negotiate in the SSL handshake phase. Notice that this
* directive can be used both in per-server and per-directory context.
* In per-server context it applies to the standard SSL handshake when a
* connection is established. In per-directory context it forces a SSL
* renegotiation with the reconfigured Cipher Suite after the HTTP request
* was read but before the HTTP response is sent.
* @param ssl the SSL instance (SSL *)
* @param ciphers an SSL cipher specification
* @param tlsv13 {@code true} if the ciphers are for TLSv1.3
* @return {@code true} if successful
* @throws Exception if an error happened
*/
public static native boolean setCipherSuites(long ssl, String ciphers, boolean tlsv13)
throws Exception;
/**
* Returns the ID of the session as byte array representation.
*
Expand Down
Expand Up @@ -110,8 +110,31 @@ public static native long make(int protocol, int mode)
* @param ciphers An SSL cipher specification.
* @return {@code true} if successful
* @throws Exception if an error happened
* @deprecated Use {@link #setCipherSuite(long, String, boolean)}.
*/
public static native boolean setCipherSuite(long ctx, String ciphers) throws Exception;
@Deprecated
public static boolean setCipherSuite(long ctx, String ciphers) throws Exception {
return setCipherSuite(ctx, ciphers, false);
}

/**
* Cipher Suite available for negotiation in SSL handshake.
* <br>
* This complex directive uses a colon-separated cipher-spec string consisting
* of OpenSSL cipher specifications to configure the Cipher Suite the client
* is permitted to negotiate in the SSL handshake phase. Notice that this
* directive can be used both in per-server and per-directory context.
* In per-server context it applies to the standard SSL handshake when a
* connection is established. In per-directory context it forces a SSL
* renegotiation with the reconfigured Cipher Suite after the HTTP request
* was read but before the HTTP response is sent.
* @param ctx Server or Client context to use.
* @param ciphers An SSL cipher specification.
* @param tlsv13 {@code true} if the ciphers are for TLSv1.3
* @return {@code true} if successful
* @throws Exception if an error happened
*/
public static native boolean setCipherSuite(long ctx, String ciphers, boolean tlsv13) throws Exception;

/**
* Set File of PEM-encoded Server CA Certificates
Expand Down
6 changes: 3 additions & 3 deletions pom.xml
Expand Up @@ -65,10 +65,10 @@
- Record the sha256: sha1sum -a 256 libressl-{libresslVersion}.tar.gz (shasum on osx)
-->
<libresslSha256>1e3a9fada06c1c060011470ad0ff960de28f9a0515277d7336f7e09362517da6</libresslSha256>
<opensslMinorVersion>1.1.0</opensslMinorVersion>
<opensslPatchVersion>i</opensslPatchVersion>
<opensslMinorVersion>1.1.1</opensslMinorVersion>
<opensslPatchVersion></opensslPatchVersion>
<opensslVersion>${opensslMinorVersion}${opensslPatchVersion}</opensslVersion>
<opensslSha256>50a98e07b1a89eb8f6a99477f262df71c6fa7bef77df4dc83025a2845c827d00</opensslSha256>
<opensslSha256>2836875a0f89c03d0fdf483941512613a50cfb421d6fd94b9f41d7279d586a3d</opensslSha256>
<aprHome>${project.build.directory}/apr</aprHome>
<aprBuildDir>${project.build.directory}/apr-${aprVersion}</aprBuildDir>
<archBits>64</archBits>
Expand Down

0 comments on commit a811c77

Please sign in to comment.