2014-05-17 19:26:01 +02:00
|
|
|
/*
|
|
|
|
* Copyright 2014 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package io.netty.handler.ssl;
|
|
|
|
|
2016-02-03 20:50:57 +01:00
|
|
|
import io.netty.buffer.ByteBuf;
|
2018-05-18 19:36:57 +02:00
|
|
|
import io.netty.buffer.ByteBufAllocator;
|
2017-07-12 21:53:39 +02:00
|
|
|
import io.netty.internal.tcnative.Buffer;
|
|
|
|
import io.netty.internal.tcnative.Library;
|
|
|
|
import io.netty.internal.tcnative.SSL;
|
|
|
|
import io.netty.internal.tcnative.SSLContext;
|
2016-08-09 18:14:22 +02:00
|
|
|
import io.netty.util.ReferenceCountUtil;
|
|
|
|
import io.netty.util.ReferenceCounted;
|
2014-05-17 19:26:01 +02:00
|
|
|
import io.netty.util.internal.NativeLibraryLoader;
|
2017-08-29 14:13:49 +02:00
|
|
|
import io.netty.util.internal.PlatformDependent;
|
2016-02-19 18:20:35 +01:00
|
|
|
import io.netty.util.internal.SystemPropertyUtil;
|
2014-05-17 19:26:01 +02:00
|
|
|
import io.netty.util.internal.logging.InternalLogger;
|
|
|
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
2016-08-10 08:55:30 +02:00
|
|
|
|
2018-10-23 17:08:23 +02:00
|
|
|
import java.io.ByteArrayInputStream;
|
2016-08-01 22:17:30 +02:00
|
|
|
import java.security.AccessController;
|
|
|
|
import java.security.PrivilegedAction;
|
2018-10-30 08:17:31 +01:00
|
|
|
import java.security.cert.CertificateException;
|
2018-10-23 17:08:23 +02:00
|
|
|
import java.security.cert.CertificateFactory;
|
|
|
|
import java.security.cert.X509Certificate;
|
2017-07-12 21:53:39 +02:00
|
|
|
import java.util.ArrayList;
|
2014-12-30 10:59:30 +01:00
|
|
|
import java.util.Collections;
|
2014-12-30 11:20:43 +01:00
|
|
|
import java.util.LinkedHashSet;
|
2017-07-12 21:53:39 +02:00
|
|
|
import java.util.List;
|
2014-12-30 11:20:43 +01:00
|
|
|
import java.util.Set;
|
2014-05-17 19:26:01 +02:00
|
|
|
|
2018-10-18 13:50:12 +02:00
|
|
|
import static io.netty.handler.ssl.SslUtils.*;
|
2017-07-12 21:53:39 +02:00
|
|
|
|
2014-05-17 19:26:01 +02:00
|
|
|
/**
|
|
|
|
* Tells if <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
|
|
|
|
* are available.
|
|
|
|
*/
|
|
|
|
public final class OpenSsl {
|
|
|
|
|
|
|
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class);
|
|
|
|
private static final Throwable UNAVAILABILITY_CAUSE;
|
|
|
|
|
2017-07-12 21:53:39 +02:00
|
|
|
static final List<String> DEFAULT_CIPHERS;
|
2016-06-22 15:46:45 +02:00
|
|
|
static final Set<String> AVAILABLE_CIPHER_SUITES;
|
|
|
|
private static final Set<String> AVAILABLE_OPENSSL_CIPHER_SUITES;
|
|
|
|
private static final Set<String> AVAILABLE_JAVA_CIPHER_SUITES;
|
2016-06-20 14:07:53 +02:00
|
|
|
private static final boolean SUPPORTS_KEYMANAGER_FACTORY;
|
2017-02-17 05:25:25 +01:00
|
|
|
private static final boolean SUPPORTS_HOSTNAME_VALIDATION;
|
2016-08-01 22:17:30 +02:00
|
|
|
private static final boolean USE_KEYMANAGER_FACTORY;
|
2017-05-09 11:41:04 +02:00
|
|
|
private static final boolean SUPPORTS_OCSP;
|
2018-10-17 08:35:35 +02:00
|
|
|
private static final boolean TLSV13_SUPPORTED;
|
2018-10-27 00:29:49 +02:00
|
|
|
private static final boolean IS_BORINGSSL;
|
2017-01-27 11:54:11 +01:00
|
|
|
static final Set<String> SUPPORTED_PROTOCOLS_SET;
|
2014-12-30 10:59:30 +01:00
|
|
|
|
2014-05-17 19:26:01 +02:00
|
|
|
static {
|
|
|
|
Throwable cause = null;
|
2015-01-08 04:23:14 +01:00
|
|
|
|
2018-05-04 14:44:44 +02:00
|
|
|
if (SystemPropertyUtil.getBoolean("io.netty.handler.ssl.noOpenSsl", false)) {
|
|
|
|
cause = new UnsupportedOperationException(
|
|
|
|
"OpenSSL was explicit disabled with -Dio.netty.handler.ssl.noOpenSsl=true");
|
2015-01-08 04:23:14 +01:00
|
|
|
|
2018-05-04 14:44:44 +02:00
|
|
|
logger.debug(
|
|
|
|
"netty-tcnative explicit disabled; " +
|
|
|
|
OpenSslEngine.class.getSimpleName() + " will be unavailable.", cause);
|
|
|
|
} else {
|
|
|
|
// Test if netty-tcnative is in the classpath first.
|
2015-01-08 04:23:14 +01:00
|
|
|
try {
|
2018-05-04 14:44:44 +02:00
|
|
|
Class.forName("io.netty.internal.tcnative.SSL", false, OpenSsl.class.getClassLoader());
|
|
|
|
} catch (ClassNotFoundException t) {
|
2016-04-11 18:06:48 +02:00
|
|
|
cause = t;
|
|
|
|
logger.debug(
|
2018-05-04 14:44:44 +02:00
|
|
|
"netty-tcnative not in the classpath; " +
|
|
|
|
OpenSslEngine.class.getSimpleName() + " will be unavailable.");
|
2016-04-11 18:06:48 +02:00
|
|
|
}
|
2016-03-02 20:18:45 +01:00
|
|
|
|
2018-05-04 14:44:44 +02:00
|
|
|
// If in the classpath, try to load the native library and initialize netty-tcnative.
|
|
|
|
if (cause == null) {
|
|
|
|
try {
|
|
|
|
// The JNI library was not already loaded. Load it now.
|
|
|
|
loadTcNative();
|
|
|
|
} catch (Throwable t) {
|
2016-04-11 18:06:48 +02:00
|
|
|
cause = t;
|
2018-05-04 14:44:44 +02:00
|
|
|
logger.debug(
|
|
|
|
"Failed to load netty-tcnative; " +
|
|
|
|
OpenSslEngine.class.getSimpleName() + " will be unavailable, unless the " +
|
|
|
|
"application has already loaded the symbols by some other means. " +
|
|
|
|
"See http://netty.io/wiki/forked-tomcat-native.html for more information.", t);
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2018-06-28 08:13:52 +02:00
|
|
|
String engine = SystemPropertyUtil.get("io.netty.handler.ssl.openssl.engine", null);
|
|
|
|
if (engine == null) {
|
|
|
|
logger.debug("Initialize netty-tcnative using engine: 'default'");
|
|
|
|
} else {
|
|
|
|
logger.debug("Initialize netty-tcnative using engine: '{}'", engine);
|
|
|
|
}
|
|
|
|
initializeTcNative(engine);
|
2018-05-04 14:44:44 +02:00
|
|
|
|
|
|
|
// The library was initialized successfully. If loading the library failed above,
|
|
|
|
// reset the cause now since it appears that the library was loaded by some other
|
|
|
|
// means.
|
|
|
|
cause = null;
|
|
|
|
} catch (Throwable t) {
|
|
|
|
if (cause == null) {
|
|
|
|
cause = t;
|
|
|
|
}
|
|
|
|
logger.debug(
|
|
|
|
"Failed to initialize netty-tcnative; " +
|
|
|
|
OpenSslEngine.class.getSimpleName() + " will be unavailable. " +
|
|
|
|
"See http://netty.io/wiki/forked-tomcat-native.html for more information.", t);
|
2016-04-11 18:06:48 +02:00
|
|
|
}
|
2015-01-08 04:23:14 +01:00
|
|
|
}
|
2014-05-17 19:26:01 +02:00
|
|
|
}
|
2015-01-08 04:23:14 +01:00
|
|
|
|
2014-05-17 19:26:01 +02:00
|
|
|
UNAVAILABILITY_CAUSE = cause;
|
2014-12-30 10:59:30 +01:00
|
|
|
|
|
|
|
if (cause == null) {
|
2017-02-19 13:34:15 +01:00
|
|
|
logger.debug("netty-tcnative using native library: {}", SSL.versionString());
|
|
|
|
|
2019-01-22 16:07:26 +01:00
|
|
|
final List<String> defaultCiphers = new ArrayList<>();
|
|
|
|
final Set<String> availableOpenSslCipherSuites = new LinkedHashSet<>(128);
|
2016-06-20 14:07:53 +02:00
|
|
|
boolean supportsKeyManagerFactory = false;
|
2016-08-01 22:17:30 +02:00
|
|
|
boolean useKeyManagerFactory = false;
|
2017-02-17 05:25:25 +01:00
|
|
|
boolean supportsHostNameValidation = false;
|
2018-10-17 08:35:35 +02:00
|
|
|
boolean tlsv13Supported = false;
|
|
|
|
|
2018-10-27 00:29:49 +02:00
|
|
|
IS_BORINGSSL = "BoringSSL".equals(versionString());
|
|
|
|
|
2014-12-30 10:59:30 +01:00
|
|
|
try {
|
2016-08-10 08:55:30 +02:00
|
|
|
final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER);
|
2016-06-20 14:07:53 +02:00
|
|
|
long certBio = 0;
|
2014-12-30 10:59:30 +01:00
|
|
|
try {
|
2018-10-18 13:50:12 +02:00
|
|
|
try {
|
2018-11-14 08:49:13 +01:00
|
|
|
StringBuilder tlsv13Ciphers = new StringBuilder();
|
|
|
|
|
|
|
|
for (String cipher: TLSV13_CIPHERS) {
|
|
|
|
String converted = CipherSuiteConverter.toOpenSsl(cipher, IS_BORINGSSL);
|
|
|
|
if (converted != null) {
|
|
|
|
tlsv13Ciphers.append(converted).append(':');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (tlsv13Ciphers.length() == 0) {
|
|
|
|
tlsv13Supported = false;
|
|
|
|
} else {
|
|
|
|
tlsv13Ciphers.setLength(tlsv13Ciphers.length() - 1);
|
|
|
|
SSLContext.setCipherSuite(sslCtx, tlsv13Ciphers.toString() , true);
|
|
|
|
tlsv13Supported = true;
|
|
|
|
}
|
|
|
|
|
2018-10-18 13:50:12 +02:00
|
|
|
} catch (Exception ignore) {
|
|
|
|
tlsv13Supported = false;
|
2018-10-17 08:35:35 +02:00
|
|
|
}
|
2018-10-18 13:50:12 +02:00
|
|
|
|
2018-10-17 08:35:35 +02:00
|
|
|
SSLContext.setCipherSuite(sslCtx, "ALL", false);
|
|
|
|
|
2014-12-30 10:59:30 +01:00
|
|
|
final long ssl = SSL.newSSL(sslCtx, true);
|
|
|
|
try {
|
|
|
|
for (String c: SSL.getCiphers(ssl)) {
|
|
|
|
// Filter out bad input.
|
2018-10-17 08:35:35 +02:00
|
|
|
if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c) ||
|
|
|
|
// Filter out TLSv1.3 ciphers if not supported.
|
2018-10-27 00:29:49 +02:00
|
|
|
!tlsv13Supported && isTLSv13Cipher(c)) {
|
2014-12-30 10:59:30 +01:00
|
|
|
continue;
|
|
|
|
}
|
2016-06-22 15:46:45 +02:00
|
|
|
availableOpenSslCipherSuites.add(c);
|
2014-12-30 10:59:30 +01:00
|
|
|
}
|
2018-10-27 00:29:49 +02:00
|
|
|
if (IS_BORINGSSL) {
|
|
|
|
// Currently BoringSSL does not include these when calling SSL.getCiphers() even when these
|
|
|
|
// are supported.
|
|
|
|
Collections.addAll(availableOpenSslCipherSuites,
|
|
|
|
"TLS_AES_128_GCM_SHA256",
|
|
|
|
"TLS_AES_256_GCM_SHA384" ,
|
2018-11-14 08:49:13 +01:00
|
|
|
"TLS_CHACHA20_POLY1305_SHA256",
|
|
|
|
"AEAD-AES128-GCM-SHA256",
|
|
|
|
"AEAD-AES256-GCM-SHA384",
|
|
|
|
"AEAD-CHACHA20-POLY1305-SHA256");
|
2018-10-27 00:29:49 +02:00
|
|
|
}
|
2017-02-17 05:25:25 +01:00
|
|
|
try {
|
|
|
|
SSL.setHostNameValidation(ssl, 0, "netty.io");
|
|
|
|
supportsHostNameValidation = true;
|
|
|
|
} catch (Throwable ignore) {
|
|
|
|
logger.debug("Hostname Verification not supported.");
|
|
|
|
}
|
2016-06-20 14:07:53 +02:00
|
|
|
try {
|
2018-10-30 08:17:31 +01:00
|
|
|
X509Certificate certificate = selfSignedCertificate();
|
2018-10-23 17:08:23 +02:00
|
|
|
certBio = ReferenceCountedOpenSslContext.toBIO(ByteBufAllocator.DEFAULT, certificate);
|
2016-06-20 14:07:53 +02:00
|
|
|
SSL.setCertificateChainBio(ssl, certBio, false);
|
|
|
|
supportsKeyManagerFactory = true;
|
2017-03-06 22:43:47 +01:00
|
|
|
try {
|
2019-01-29 14:06:05 +01:00
|
|
|
useKeyManagerFactory = AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
|
|
|
|
SystemPropertyUtil.getBoolean(
|
|
|
|
"io.netty.handler.ssl.openssl.useKeyManagerFactory", true));
|
2017-03-06 22:43:47 +01:00
|
|
|
} catch (Throwable ignore) {
|
|
|
|
logger.debug("Failed to get useKeyManagerFactory system property.");
|
|
|
|
}
|
2016-06-20 14:07:53 +02:00
|
|
|
} catch (Throwable ignore) {
|
|
|
|
logger.debug("KeyManagerFactory not supported.");
|
|
|
|
}
|
2014-12-30 10:59:30 +01:00
|
|
|
} finally {
|
|
|
|
SSL.freeSSL(ssl);
|
2016-06-20 14:07:53 +02:00
|
|
|
if (certBio != 0) {
|
|
|
|
SSL.freeBIO(certBio);
|
|
|
|
}
|
2014-12-30 10:59:30 +01:00
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
SSLContext.free(sslCtx);
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
logger.warn("Failed to get the list of available OpenSSL cipher suites.", e);
|
|
|
|
}
|
2016-06-22 15:46:45 +02:00
|
|
|
AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites);
|
2019-01-22 16:07:26 +01:00
|
|
|
final Set<String> availableJavaCipherSuites = new LinkedHashSet<>(
|
2016-06-22 15:46:45 +02:00
|
|
|
AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2);
|
|
|
|
for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) {
|
|
|
|
// Included converted but also openssl cipher name
|
2018-10-27 00:29:49 +02:00
|
|
|
if (!isTLSv13Cipher(cipher)) {
|
2018-10-17 08:35:35 +02:00
|
|
|
availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS"));
|
|
|
|
availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL"));
|
|
|
|
} else {
|
|
|
|
// TLSv1.3 ciphers have the correct format.
|
|
|
|
availableJavaCipherSuites.add(cipher);
|
|
|
|
}
|
2016-06-22 15:46:45 +02:00
|
|
|
}
|
2017-07-12 21:53:39 +02:00
|
|
|
|
2017-11-28 12:04:38 +01:00
|
|
|
addIfSupported(availableJavaCipherSuites, defaultCiphers, DEFAULT_CIPHER_SUITES);
|
2018-10-18 13:50:12 +02:00
|
|
|
addIfSupported(availableJavaCipherSuites, defaultCiphers, TLSV13_CIPHER_SUITES);
|
|
|
|
|
2017-07-12 21:53:39 +02:00
|
|
|
useFallbackCiphersIfDefaultIsEmpty(defaultCiphers, availableJavaCipherSuites);
|
|
|
|
DEFAULT_CIPHERS = Collections.unmodifiableList(defaultCiphers);
|
|
|
|
|
2016-06-22 15:46:45 +02:00
|
|
|
AVAILABLE_JAVA_CIPHER_SUITES = Collections.unmodifiableSet(availableJavaCipherSuites);
|
|
|
|
|
2019-01-22 16:07:26 +01:00
|
|
|
final Set<String> availableCipherSuites = new LinkedHashSet<>(
|
2016-06-22 15:46:45 +02:00
|
|
|
AVAILABLE_OPENSSL_CIPHER_SUITES.size() + AVAILABLE_JAVA_CIPHER_SUITES.size());
|
2017-05-09 12:53:55 +02:00
|
|
|
availableCipherSuites.addAll(AVAILABLE_OPENSSL_CIPHER_SUITES);
|
|
|
|
availableCipherSuites.addAll(AVAILABLE_JAVA_CIPHER_SUITES);
|
|
|
|
|
2016-06-22 15:46:45 +02:00
|
|
|
AVAILABLE_CIPHER_SUITES = availableCipherSuites;
|
2016-06-20 14:07:53 +02:00
|
|
|
SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory;
|
2017-02-17 05:25:25 +01:00
|
|
|
SUPPORTS_HOSTNAME_VALIDATION = supportsHostNameValidation;
|
2016-08-01 22:17:30 +02:00
|
|
|
USE_KEYMANAGER_FACTORY = useKeyManagerFactory;
|
2017-01-27 11:54:11 +01:00
|
|
|
|
2019-01-22 16:07:26 +01:00
|
|
|
Set<String> protocols = new LinkedHashSet<>(6);
|
2017-01-27 11:54:11 +01:00
|
|
|
// Seems like there is no way to explicitly disable SSLv2Hello in openssl so it is always enabled
|
|
|
|
protocols.add(PROTOCOL_SSL_V2_HELLO);
|
2018-05-16 07:23:55 +02:00
|
|
|
if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2, SSL.SSL_OP_NO_SSLv2)) {
|
2016-08-10 08:55:30 +02:00
|
|
|
protocols.add(PROTOCOL_SSL_V2);
|
|
|
|
}
|
2018-05-16 07:23:55 +02:00
|
|
|
if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3, SSL.SSL_OP_NO_SSLv3)) {
|
2016-08-10 08:55:30 +02:00
|
|
|
protocols.add(PROTOCOL_SSL_V3);
|
|
|
|
}
|
2018-05-16 07:23:55 +02:00
|
|
|
if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1, SSL.SSL_OP_NO_TLSv1)) {
|
2016-08-10 08:55:30 +02:00
|
|
|
protocols.add(PROTOCOL_TLS_V1);
|
2017-01-27 11:54:11 +01:00
|
|
|
}
|
2018-05-16 07:23:55 +02:00
|
|
|
if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1, SSL.SSL_OP_NO_TLSv1_1)) {
|
2016-08-10 08:55:30 +02:00
|
|
|
protocols.add(PROTOCOL_TLS_V1_1);
|
|
|
|
}
|
2018-05-16 07:23:55 +02:00
|
|
|
if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_OP_NO_TLSv1_2)) {
|
2016-08-10 08:55:30 +02:00
|
|
|
protocols.add(PROTOCOL_TLS_V1_2);
|
|
|
|
}
|
|
|
|
|
2018-10-17 08:35:35 +02:00
|
|
|
// This is only supported by java11 and later.
|
2018-10-18 13:50:12 +02:00
|
|
|
if (tlsv13Supported && doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_3, SSL.SSL_OP_NO_TLSv1_3)) {
|
2018-10-17 08:35:35 +02:00
|
|
|
protocols.add(PROTOCOL_TLS_V1_3);
|
|
|
|
TLSV13_SUPPORTED = true;
|
|
|
|
} else {
|
|
|
|
TLSV13_SUPPORTED = false;
|
|
|
|
}
|
|
|
|
|
2017-01-27 11:54:11 +01:00
|
|
|
SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet(protocols);
|
2017-05-09 11:41:04 +02:00
|
|
|
SUPPORTS_OCSP = doesSupportOcsp();
|
2017-07-12 21:53:39 +02:00
|
|
|
|
|
|
|
if (logger.isDebugEnabled()) {
|
2018-05-16 07:23:55 +02:00
|
|
|
logger.debug("Supported protocols (OpenSSL): {} ", SUPPORTED_PROTOCOLS_SET);
|
2017-07-12 21:53:39 +02:00
|
|
|
logger.debug("Default cipher suites (OpenSSL): {}", DEFAULT_CIPHERS);
|
|
|
|
}
|
2014-12-30 10:59:30 +01:00
|
|
|
} else {
|
2017-07-12 21:53:39 +02:00
|
|
|
DEFAULT_CIPHERS = Collections.emptyList();
|
2016-06-22 15:46:45 +02:00
|
|
|
AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet();
|
|
|
|
AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet();
|
2014-12-30 11:20:43 +01:00
|
|
|
AVAILABLE_CIPHER_SUITES = Collections.emptySet();
|
2016-06-20 14:07:53 +02:00
|
|
|
SUPPORTS_KEYMANAGER_FACTORY = false;
|
2017-02-17 05:25:25 +01:00
|
|
|
SUPPORTS_HOSTNAME_VALIDATION = false;
|
2016-08-01 22:17:30 +02:00
|
|
|
USE_KEYMANAGER_FACTORY = false;
|
2017-01-27 11:54:11 +01:00
|
|
|
SUPPORTED_PROTOCOLS_SET = Collections.emptySet();
|
2017-05-09 11:41:04 +02:00
|
|
|
SUPPORTS_OCSP = false;
|
2018-10-17 08:35:35 +02:00
|
|
|
TLSV13_SUPPORTED = false;
|
2018-10-27 00:29:49 +02:00
|
|
|
IS_BORINGSSL = false;
|
2017-01-27 11:54:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-30 08:17:31 +01:00
|
|
|
/**
|
|
|
|
* Returns a self-signed {@link X509Certificate} for {@code netty.io}.
|
|
|
|
*/
|
|
|
|
static X509Certificate selfSignedCertificate() throws CertificateException {
|
|
|
|
// Bytes of self-signed certificate for netty.io
|
|
|
|
byte[] certBytes = {
|
|
|
|
48, -126, 1, -92, 48, -126, 1, 13, -96, 3, 2, 1, 2, 2, 9, 0, -9, 61,
|
|
|
|
44, 121, -118, -4, -45, -120, 48, 13, 6, 9, 42, -122, 72, -122,
|
|
|
|
-9, 13, 1, 1, 5, 5, 0, 48, 19, 49, 17, 48, 15, 6, 3, 85, 4, 3, 19,
|
|
|
|
8, 110, 101, 116, 116, 121, 46, 105, 111, 48, 32, 23, 13, 49, 55,
|
|
|
|
49, 48, 50, 48, 49, 56, 49, 54, 51, 54, 90, 24, 15, 57, 57, 57, 57,
|
|
|
|
49, 50, 51, 49, 50, 51, 53, 57, 53, 57, 90, 48, 19, 49, 17, 48, 15,
|
|
|
|
6, 3, 85, 4, 3, 19, 8, 110, 101, 116, 116, 121, 46, 105, 111, 48, -127,
|
|
|
|
-97, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -127,
|
|
|
|
-115, 0, 48, -127, -119, 2, -127, -127, 0, -116, 37, 122, -53, 28, 46,
|
|
|
|
13, -90, -14, -33, 111, -108, -41, 59, 90, 124, 113, -112, -66, -17,
|
|
|
|
-102, 44, 13, 7, -33, -28, 24, -79, -126, -76, 40, 111, -126, -103,
|
|
|
|
-102, 34, 11, 45, 16, -38, 63, 24, 80, 24, 76, 88, -93, 96, 11, 38,
|
|
|
|
-19, -64, -11, 87, -49, -52, -65, 24, 36, -22, 53, 8, -42, 14, -121,
|
|
|
|
114, 6, 17, -82, 10, 92, -91, -127, 81, -12, -75, 105, -10, -106, 91,
|
|
|
|
-38, 111, 50, 57, -97, -125, 109, 42, -87, -1, -19, 80, 78, 49, -97, -4,
|
|
|
|
23, -2, -103, 122, -107, -43, 4, -31, -21, 90, 39, -9, -106, 34, -101,
|
|
|
|
-116, 31, -94, -84, 80, -6, -78, -33, 87, -90, 31, 103, 100, 56, -103,
|
|
|
|
-5, 11, 2, 3, 1, 0, 1, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1,
|
|
|
|
5, 5, 0, 3, -127, -127, 0, 112, 45, -73, 5, 64, 49, 59, 101, 51, 73,
|
|
|
|
-96, 62, 23, -84, 90, -41, -58, 83, -20, -72, 38, 123, -108, -45, 28,
|
|
|
|
96, -122, -18, 30, 42, 86, 87, -87, -28, 107, 110, 11, -59, 91, 100,
|
|
|
|
101, -18, 26, -103, -78, -80, -3, 38, 113, 83, -48, -108, 109, 41, -15,
|
|
|
|
6, 112, 105, 7, -46, -11, -3, -51, 40, -66, -73, -83, -46, -94, -121,
|
|
|
|
-88, 51, -106, -77, 109, 53, -7, 123, 91, 75, -105, -22, 64, 121, -72,
|
|
|
|
-59, -21, -44, 84, 12, 9, 120, 21, -26, 13, 49, -81, -58, -47, 117,
|
|
|
|
-44, -18, -17, 124, 49, -48, 19, 16, -41, 71, -52, -107, 99, -19, -29,
|
|
|
|
105, -93, -71, -38, -97, -128, -2, 118, 119, 49, -126, 109, 119 };
|
|
|
|
|
|
|
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
|
|
|
return (X509Certificate) cf.generateCertificate(
|
|
|
|
new ByteArrayInputStream(certBytes));
|
|
|
|
}
|
|
|
|
|
2017-05-09 11:41:04 +02:00
|
|
|
private static boolean doesSupportOcsp() {
|
|
|
|
boolean supportsOcsp = false;
|
|
|
|
if (version() >= 0x10002000L) {
|
|
|
|
long sslCtx = -1;
|
|
|
|
try {
|
|
|
|
sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_MODE_SERVER);
|
|
|
|
SSLContext.enableOcsp(sslCtx, false);
|
|
|
|
supportsOcsp = true;
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
// ignore
|
|
|
|
} finally {
|
|
|
|
if (sslCtx != -1) {
|
|
|
|
SSLContext.free(sslCtx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return supportsOcsp;
|
|
|
|
}
|
2018-05-16 07:23:55 +02:00
|
|
|
private static boolean doesSupportProtocol(int protocol, int opt) {
|
|
|
|
if (opt == 0) {
|
|
|
|
// If the opt is 0 the protocol is not supported. This is for example the case with BoringSSL and SSLv2.
|
|
|
|
return false;
|
|
|
|
}
|
2017-01-27 11:54:11 +01:00
|
|
|
long sslCtx = -1;
|
|
|
|
try {
|
2016-08-10 08:55:30 +02:00
|
|
|
sslCtx = SSLContext.make(protocol, SSL.SSL_MODE_COMBINED);
|
2017-01-27 11:54:11 +01:00
|
|
|
return true;
|
|
|
|
} catch (Exception ignore) {
|
|
|
|
return false;
|
|
|
|
} finally {
|
|
|
|
if (sslCtx != -1) {
|
|
|
|
SSLContext.free(sslCtx);
|
|
|
|
}
|
2014-12-30 10:59:30 +01:00
|
|
|
}
|
2014-05-17 19:26:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns {@code true} if and only if
|
|
|
|
* <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
|
|
|
|
* are available.
|
|
|
|
*/
|
|
|
|
public static boolean isAvailable() {
|
|
|
|
return UNAVAILABILITY_CAUSE == null;
|
|
|
|
}
|
|
|
|
|
2015-03-05 14:19:13 +01:00
|
|
|
/**
|
|
|
|
* Returns {@code true} if the used version of openssl supports
|
|
|
|
* <a href="https://tools.ietf.org/html/rfc7301">ALPN</a>.
|
|
|
|
*/
|
|
|
|
public static boolean isAlpnSupported() {
|
2015-04-15 23:05:10 +02:00
|
|
|
return version() >= 0x10002000L;
|
|
|
|
}
|
|
|
|
|
2016-12-27 00:04:56 +01:00
|
|
|
/**
|
|
|
|
* Returns {@code true} if the used version of OpenSSL supports OCSP stapling.
|
|
|
|
*/
|
|
|
|
public static boolean isOcspSupported() {
|
2017-05-09 11:41:04 +02:00
|
|
|
return SUPPORTS_OCSP;
|
2016-12-27 00:04:56 +01:00
|
|
|
}
|
|
|
|
|
2015-04-15 23:05:10 +02:00
|
|
|
/**
|
|
|
|
* Returns the version of the used available OpenSSL library or {@code -1} if {@link #isAvailable()}
|
|
|
|
* returns {@code false}.
|
|
|
|
*/
|
|
|
|
public static int version() {
|
2017-05-09 12:53:55 +02:00
|
|
|
return isAvailable() ? SSL.version() : -1;
|
2015-04-15 23:05:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the version string of the used available OpenSSL library or {@code null} if {@link #isAvailable()}
|
|
|
|
* returns {@code false}.
|
|
|
|
*/
|
|
|
|
public static String versionString() {
|
2017-05-09 12:53:55 +02:00
|
|
|
return isAvailable() ? SSL.versionString() : null;
|
2015-03-05 14:19:13 +01:00
|
|
|
}
|
|
|
|
|
2014-05-17 19:26:01 +02:00
|
|
|
/**
|
|
|
|
* Ensure that <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and
|
|
|
|
* its OpenSSL support are available.
|
|
|
|
*
|
|
|
|
* @throws UnsatisfiedLinkError if unavailable
|
|
|
|
*/
|
|
|
|
public static void ensureAvailability() {
|
|
|
|
if (UNAVAILABILITY_CAUSE != null) {
|
|
|
|
throw (Error) new UnsatisfiedLinkError(
|
|
|
|
"failed to load the required native library").initCause(UNAVAILABILITY_CAUSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the cause of unavailability of
|
|
|
|
* <a href="http://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support.
|
|
|
|
*
|
|
|
|
* @return the cause if unavailable. {@code null} if available.
|
|
|
|
*/
|
|
|
|
public static Throwable unavailabilityCause() {
|
|
|
|
return UNAVAILABILITY_CAUSE;
|
|
|
|
}
|
|
|
|
|
2016-06-22 15:46:45 +02:00
|
|
|
/**
|
|
|
|
* @deprecated use {@link #availableOpenSslCipherSuites()}
|
|
|
|
*/
|
|
|
|
@Deprecated
|
|
|
|
public static Set<String> availableCipherSuites() {
|
|
|
|
return availableOpenSslCipherSuites();
|
|
|
|
}
|
|
|
|
|
2014-12-30 10:59:30 +01:00
|
|
|
/**
|
|
|
|
* Returns all the available OpenSSL cipher suites.
|
|
|
|
* Please note that the returned array may include the cipher suites that are insecure or non-functional.
|
|
|
|
*/
|
2016-06-22 15:46:45 +02:00
|
|
|
public static Set<String> availableOpenSslCipherSuites() {
|
|
|
|
return AVAILABLE_OPENSSL_CIPHER_SUITES;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns all the available cipher suites (Java-style).
|
|
|
|
* Please note that the returned array may include the cipher suites that are insecure or non-functional.
|
|
|
|
*/
|
|
|
|
public static Set<String> availableJavaCipherSuites() {
|
|
|
|
return AVAILABLE_JAVA_CIPHER_SUITES;
|
2014-12-30 11:20:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns {@code true} if and only if the specified cipher suite is available in OpenSSL.
|
|
|
|
* Both Java-style cipher suite and OpenSSL-style cipher suite are accepted.
|
|
|
|
*/
|
|
|
|
public static boolean isCipherSuiteAvailable(String cipherSuite) {
|
2018-11-14 08:49:13 +01:00
|
|
|
String converted = CipherSuiteConverter.toOpenSsl(cipherSuite, IS_BORINGSSL);
|
2014-12-30 11:20:43 +01:00
|
|
|
if (converted != null) {
|
|
|
|
cipherSuite = converted;
|
|
|
|
}
|
2016-06-22 15:46:45 +02:00
|
|
|
return AVAILABLE_OPENSSL_CIPHER_SUITES.contains(cipherSuite);
|
2014-12-30 10:59:30 +01:00
|
|
|
}
|
|
|
|
|
2016-06-20 14:07:53 +02:00
|
|
|
/**
|
|
|
|
* Returns {@code true} if {@link javax.net.ssl.KeyManagerFactory} is supported when using OpenSSL.
|
|
|
|
*/
|
|
|
|
public static boolean supportsKeyManagerFactory() {
|
|
|
|
return SUPPORTS_KEYMANAGER_FACTORY;
|
|
|
|
}
|
|
|
|
|
2017-02-17 05:25:25 +01:00
|
|
|
/**
|
|
|
|
* Returns {@code true} if <a href="https://wiki.openssl.org/index.php/Hostname_validation">Hostname Validation</a>
|
|
|
|
* is supported when using OpenSSL.
|
|
|
|
*/
|
|
|
|
public static boolean supportsHostnameValidation() {
|
|
|
|
return SUPPORTS_HOSTNAME_VALIDATION;
|
|
|
|
}
|
|
|
|
|
2016-08-01 22:17:30 +02:00
|
|
|
static boolean useKeyManagerFactory() {
|
|
|
|
return USE_KEYMANAGER_FACTORY;
|
|
|
|
}
|
|
|
|
|
2016-02-03 20:50:57 +01:00
|
|
|
static long memoryAddress(ByteBuf buf) {
|
|
|
|
assert buf.isDirect();
|
|
|
|
return buf.hasMemoryAddress() ? buf.memoryAddress() : Buffer.address(buf.nioBuffer());
|
|
|
|
}
|
|
|
|
|
2014-05-17 19:26:01 +02:00
|
|
|
private OpenSsl() { }
|
2016-02-19 18:20:35 +01:00
|
|
|
|
2016-04-11 18:06:48 +02:00
|
|
|
private static void loadTcNative() throws Exception {
|
2017-08-29 14:13:49 +02:00
|
|
|
String os = PlatformDependent.normalizedOs();
|
|
|
|
String arch = PlatformDependent.normalizedArch();
|
2016-04-11 18:06:48 +02:00
|
|
|
|
2019-01-22 16:07:26 +01:00
|
|
|
Set<String> libNames = new LinkedHashSet<>(4);
|
2017-10-24 19:52:55 +02:00
|
|
|
String staticLibName = "netty_tcnative";
|
|
|
|
|
2016-04-11 18:06:48 +02:00
|
|
|
// First, try loading the platform-specific library. Platform-specific
|
|
|
|
// libraries will be available if using a tcnative uber jar.
|
2017-10-24 19:52:55 +02:00
|
|
|
libNames.add(staticLibName + "_" + os + '_' + arch);
|
2017-08-29 14:13:49 +02:00
|
|
|
if ("linux".equalsIgnoreCase(os)) {
|
2016-04-11 18:06:48 +02:00
|
|
|
// Fedora SSL lib so naming (libssl.so.10 vs libssl.so.1.0.0)..
|
2017-10-24 19:52:55 +02:00
|
|
|
libNames.add(staticLibName + "_" + os + '_' + arch + "_fedora");
|
2016-04-11 18:06:48 +02:00
|
|
|
}
|
2017-10-24 19:52:55 +02:00
|
|
|
libNames.add(staticLibName + "_" + arch);
|
|
|
|
libNames.add(staticLibName);
|
2016-04-11 18:06:48 +02:00
|
|
|
|
|
|
|
NativeLibraryLoader.loadFirstAvailable(SSL.class.getClassLoader(),
|
2018-06-29 07:56:04 +02:00
|
|
|
libNames.toArray(new String[0]));
|
2016-04-11 18:06:48 +02:00
|
|
|
}
|
|
|
|
|
2018-06-28 08:13:52 +02:00
|
|
|
private static boolean initializeTcNative(String engine) throws Exception {
|
|
|
|
return Library.initialize("provided", engine);
|
2016-04-11 18:06:48 +02:00
|
|
|
}
|
|
|
|
|
2016-08-09 18:14:22 +02:00
|
|
|
static void releaseIfNeeded(ReferenceCounted counted) {
|
|
|
|
if (counted.refCnt() > 0) {
|
|
|
|
ReferenceCountUtil.safeRelease(counted);
|
|
|
|
}
|
|
|
|
}
|
2018-10-17 08:35:35 +02:00
|
|
|
|
|
|
|
static boolean isTlsv13Supported() {
|
|
|
|
return TLSV13_SUPPORTED;
|
|
|
|
}
|
2018-10-27 00:29:49 +02:00
|
|
|
|
|
|
|
static boolean isBoringSSL() {
|
|
|
|
return IS_BORINGSSL;
|
|
|
|
}
|
2014-05-17 19:26:01 +02:00
|
|
|
}
|