Skip to content

Commit

Permalink
Add TlsEngineType enum (#5029)
Browse files Browse the repository at this point in the history
Motivation:

Add `TlsEngineType` to let users choose the type of tls engine. (Using
`Flags`)

Modifications:

- Add `TlsEngineType` enum 
- Deprecate `useOpenSsl` 

Result:

- Related to #<[4949](#4949)>.
- Related to
#4962 (comment)
- `TlsEngineType` is added 
- `useOpenSsl` is deprecated 

<!--
Visit this URL to learn more about how to write a pull request
description:

https://armeria.dev/community/developer-guide#how-to-write-pull-request-description
-->

---------

Co-authored-by: Ikhun Um <[email protected]>
Co-authored-by: Ikhun Um <[email protected]>
Co-authored-by: jrhee17 <[email protected]>
Co-authored-by: minwoox <[email protected]>
Co-authored-by: minux <[email protected]>
  • Loading branch information
6 people authored Apr 3, 2024
1 parent c8cc094 commit 33ab3bb
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.google.common.collect.ImmutableSet;

import com.linecorp.armeria.common.util.Sampler;
import com.linecorp.armeria.common.util.TlsEngineType;
import com.linecorp.armeria.common.util.TransportType;
import com.linecorp.armeria.server.TransientServiceOption;

Expand Down Expand Up @@ -160,6 +161,11 @@ public Boolean useOpenSsl() {
return true;
}

@Override
public TlsEngineType tlsEngineType() {
return TlsEngineType.OPENSSL;
}

@Override
public Boolean dumpOpenSslInfo() {
return false;
Expand Down
99 changes: 73 additions & 26 deletions core/src/main/java/com/linecorp/armeria/common/Flags.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import com.linecorp.armeria.common.util.Exceptions;
import com.linecorp.armeria.common.util.Sampler;
import com.linecorp.armeria.common.util.SystemInfo;
import com.linecorp.armeria.common.util.TlsEngineType;
import com.linecorp.armeria.common.util.TransportType;
import com.linecorp.armeria.internal.common.FlagsLoaded;
import com.linecorp.armeria.internal.common.util.SslContextUtil;
Expand Down Expand Up @@ -107,7 +108,6 @@ public final class Flags {
.sorted(Comparator.comparingInt(FlagsProvider::priority).reversed())
.collect(Collectors.toList());
flagsProviders.add(0, SystemPropertyFlagsProvider.INSTANCE);
flagsProviders.add(DefaultFlagsProvider.INSTANCE);
FLAGS_PROVIDERS = ImmutableList.copyOf(flagsProviders);
}

Expand Down Expand Up @@ -190,7 +190,8 @@ private static boolean validateTransportType(TransportType transportType, String
getValue(FlagsProvider::transportType, "transportType", TRANSPORT_TYPE_VALIDATOR);

@Nullable
private static Boolean useOpenSsl;
private static TlsEngineType tlsEngineType;

@Nullable
private static Boolean dumpOpenSslInfo;

Expand Down Expand Up @@ -431,7 +432,6 @@ public static Sampler<Class<? extends Throwable>> verboseExceptionSampler() {
* stack trace of the exceptions that are thrown frequently by Armeria.
*
* @see #verboseExceptionSampler()
*
* @deprecated Use {@link #verboseExceptionSampler()} and
* {@code -Dcom.linecorp.armeria.verboseExceptions=<specification>}.
*/
Expand Down Expand Up @@ -540,32 +540,67 @@ public static TransportType transportType() {
*
* <p>This flag is enabled by default for supported platforms. Specify the
* {@code -Dcom.linecorp.armeria.useOpenSsl=false} JVM option to disable it.
*
* @deprecated Use {@link #tlsEngineType()} and {@code -Dcom.linecorp.armeria.tlsEngineType=openssl}.
*/
@Deprecated
public static boolean useOpenSsl() {
if (useOpenSsl != null) {
return useOpenSsl;
return tlsEngineType() == TlsEngineType.OPENSSL;
}

/**
* Returns the {@link TlsEngineType} that will be used for processing TLS connections.
*
* <p>The default value of this flag is {@link TlsEngineType#OPENSSL}.
* Specify the {@code -Dcom.linecorp.armeria.tlsEngineType=<jdk|openssl>} JVM option to override
* the default value.
*/
@UnstableApi
public static TlsEngineType tlsEngineType() {
if (tlsEngineType != null) {
return tlsEngineType;
}
setUseOpenSslAndDumpOpenSslInfo();
return useOpenSsl;
detectTlsEngineAndDumpOpenSslInfo();
return tlsEngineType;
}

private static void setUseOpenSslAndDumpOpenSslInfo() {
final boolean useOpenSsl = getValue(FlagsProvider::useOpenSsl, "useOpenSsl");
if (!useOpenSsl) {
// OpenSSL explicitly disabled
Flags.useOpenSsl = false;
dumpOpenSslInfo = false;
return;
private static void detectTlsEngineAndDumpOpenSslInfo() {

final Boolean useOpenSsl = getUserValue(FlagsProvider::useOpenSsl, "useOpenSsl",
ignored -> true);
final TlsEngineType tlsEngineTypeValue = getUserValue(FlagsProvider::tlsEngineType,
"tlsEngineType", ignored -> true);

if (useOpenSsl != null && (useOpenSsl != (tlsEngineTypeValue == TlsEngineType.OPENSSL))) {
logger.warn("useOpenSsl({}) and tlsEngineType({}) are incompatible, tlsEngineType will be used",
useOpenSsl, tlsEngineTypeValue);
}

TlsEngineType preferredTlsEngineType = null;
if (tlsEngineTypeValue != null) {
preferredTlsEngineType = tlsEngineTypeValue;
} else if (useOpenSsl != null) {
preferredTlsEngineType = useOpenSsl ? TlsEngineType.OPENSSL : TlsEngineType.JDK;
}
if (preferredTlsEngineType == TlsEngineType.OPENSSL) {
if (!OpenSsl.isAvailable()) {
final Throwable cause = Exceptions.peel(OpenSsl.unavailabilityCause());
logger.info("OpenSSL not available: {}", cause.toString());
preferredTlsEngineType = TlsEngineType.JDK;
}
}
if (preferredTlsEngineType == null) {
preferredTlsEngineType = OpenSsl.isAvailable() ? TlsEngineType.OPENSSL : TlsEngineType.JDK;
}
if (!OpenSsl.isAvailable()) {
final Throwable cause = Exceptions.peel(OpenSsl.unavailabilityCause());
logger.info("OpenSSL not available: {}", cause.toString());
Flags.useOpenSsl = false;
tlsEngineType = preferredTlsEngineType;

if (tlsEngineType != TlsEngineType.OPENSSL) {
dumpOpenSslInfo = false;
logger.info("Using TLS engine: {}", tlsEngineType);
return;
}
Flags.useOpenSsl = true;
logger.info("Using OpenSSL: {}, 0x{}", OpenSsl.versionString(),

logger.info("Using Tls engine: OpenSSL {}, 0x{}", OpenSsl.versionString(),
Long.toHexString(OpenSsl.version() & 0xFFFFFFFFL));
dumpOpenSslInfo = getValue(FlagsProvider::dumpOpenSslInfo, "dumpOpenSslInfo");
if (dumpOpenSslInfo) {
Expand All @@ -590,14 +625,14 @@ private static void setUseOpenSslAndDumpOpenSslInfo() {
* <p>This flag is disabled by default. Specify the {@code -Dcom.linecorp.armeria.dumpOpenSslInfo=true} JVM
* option to enable it.
*
* <p>If {@link #useOpenSsl()} returns {@code false}, this also returns {@code false} no matter you
* specified the JVM option.
* <p>If {@link #tlsEngineType()} does not return {@link TlsEngineType#OPENSSL}, this also returns
* {@code false} no matter what the specified JVM option is.
*/
public static boolean dumpOpenSslInfo() {
if (dumpOpenSslInfo != null) {
return dumpOpenSslInfo;
}
setUseOpenSslAndDumpOpenSslInfo();
detectTlsEngineAndDumpOpenSslInfo();
return dumpOpenSslInfo;
}

Expand Down Expand Up @@ -1236,7 +1271,6 @@ public static String dnsCacheSpec() {
* to override the default value.
*
* @see ExceptionVerbosity
*
* @deprecated Use {@link LoggingService} or log exceptions using
* {@link ServerBuilder#errorHandler(ServerErrorHandler)}.
*/
Expand Down Expand Up @@ -1589,24 +1623,37 @@ private static <T> T getValue(Function<FlagsProvider, @Nullable T> method, Strin

private static <T> T getValue(Function<FlagsProvider, @Nullable T> method,
String flagName, Predicate<T> validator) {
final T t = getUserValue(method, flagName, validator);
if (t != null) {
return t;
}

return method.apply(DefaultFlagsProvider.INSTANCE);
}

@Nullable
private static <T> T getUserValue(Function<FlagsProvider, @Nullable T> method, String flagName,
Predicate<T> validator) {
for (FlagsProvider provider : FLAGS_PROVIDERS) {
try {
final T value = method.apply(provider);
if (value == null) {
continue;
}

if (!validator.test(value)) {
logger.warn("{}: {} ({}, validation failed)", flagName, value, provider.name());
continue;
}

logger.info("{}: {} ({})", flagName, value, provider.name());
return value;
} catch (Exception ex) {
logger.warn("{}: ({}, {})", flagName, provider.name(), ex.getMessage());
}
}
// Should never reach here because DefaultFlagsProvider always returns a normal value.
throw new Error();

return null;
}

private Flags() {}
Expand Down
20 changes: 18 additions & 2 deletions core/src/main/java/com/linecorp/armeria/common/FlagsProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import com.linecorp.armeria.common.util.Exceptions;
import com.linecorp.armeria.common.util.Sampler;
import com.linecorp.armeria.common.util.SystemInfo;
import com.linecorp.armeria.common.util.TlsEngineType;
import com.linecorp.armeria.common.util.TransportType;
import com.linecorp.armeria.server.HttpService;
import com.linecorp.armeria.server.ServerBuilder;
Expand Down Expand Up @@ -198,21 +199,36 @@ default TransportType transportType() {
*
* <p>This flag is enabled by default for supported platforms. Specify the
* {@code -Dcom.linecorp.armeria.useOpenSsl=false} JVM option to disable it.
*
* @deprecated Use {@link #tlsEngineType()} and {@code -Dcom.linecorp.armeria.tlsEngineType=openssl}.
*/
@Nullable
@Deprecated
default Boolean useOpenSsl() {
return null;
}

/**
* Returns the {@link TlsEngineType} that will be used for processing TLS connections.
*
* <p>The default value of this flag is "openssl", which means the {@link TlsEngineType#OPENSSL} will
* be used. Specify the {@code -Dcom.linecorp.armeria.tlsEngineType=<jdk|openssl>} JVM option to override
* the default.</p>
*/
@Nullable
default TlsEngineType tlsEngineType() {
return null;
}

/**
* Returns whether information about the OpenSSL environment should be dumped when first starting the
* application, including supported ciphers.
*
* <p>This flag is disabled by default. Specify the {@code -Dcom.linecorp.armeria.dumpOpenSslInfo=true} JVM
* option to enable it.
*
* <p>If {@link #useOpenSsl()} returns {@code false}, this also returns {@code false} no matter you
* specified the JVM option.
* <p>If {@link #tlsEngineType()} does not return {@link TlsEngineType#OPENSSL}, this also returns
* {@code false} no matter what the specified JVM option is.
*/
@Nullable
default Boolean dumpOpenSslInfo() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.linecorp.armeria.common.annotation.Nullable;
import com.linecorp.armeria.common.util.InetAddressPredicates;
import com.linecorp.armeria.common.util.Sampler;
import com.linecorp.armeria.common.util.TlsEngineType;
import com.linecorp.armeria.common.util.TransportType;
import com.linecorp.armeria.server.TransientServiceOption;

Expand Down Expand Up @@ -148,6 +149,23 @@ public Boolean useOpenSsl() {
return getBoolean("useOpenSsl");
}

@Override
public TlsEngineType tlsEngineType() {
final String strTlsEngineType = getNormalized("tlsEngineType");
if (strTlsEngineType == null) {
return null;
}
switch (strTlsEngineType) {
case "jdk":
return TlsEngineType.JDK;
case "openssl":
return TlsEngineType.OPENSSL;
default:
throw new IllegalArgumentException(
String.format("%s isn't one of 'jdk' or 'openssl'", strTlsEngineType));
}
}

@Override
public Boolean dumpOpenSslInfo() {
return getBoolean("dumpOpenSslInfo");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2023 LINE Corporation
*
* LINE Corporation 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:
*
* https://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 com.linecorp.armeria.common.util;

import com.linecorp.armeria.common.annotation.UnstableApi;

import io.netty.handler.ssl.SslProvider;

/**
* Tls engine types.
*/
@UnstableApi
public enum TlsEngineType {
/**
* JDK's default implementation.
*/
JDK(SslProvider.JDK),
/**
* OpenSSL-based implementation.
*/
OPENSSL(SslProvider.OPENSSL);

private final SslProvider sslProvider;

TlsEngineType(SslProvider sslProvider) {
this.sslProvider = sslProvider;
}

/**
* Returns the {@link SslProvider} corresponding to this {@link TlsEngineType}.
*/
public SslProvider sslProvider() {
return sslProvider;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public static SslContext createSslContext(

return MinifiedBouncyCastleProvider.call(() -> {
final SslContextBuilder builder = builderSupplier.get();
final SslProvider provider = Flags.useOpenSsl() ? SslProvider.OPENSSL : SslProvider.JDK;
final SslProvider provider = Flags.tlsEngineType().sslProvider();
builder.sslProvider(provider);

final Set<String> supportedProtocols = supportedProtocols(builder);
Expand Down Expand Up @@ -147,7 +147,7 @@ public static SslContext createSslContext(
"You must specify at least one cipher suite.");

if (forceHttp1) {
// Skip validation
// Skip validation
} else {
validateHttp2Ciphers(ciphers, tlsAllowUnsafeCiphers);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
import com.linecorp.armeria.common.util.EventLoopGroups;
import com.linecorp.armeria.common.util.SystemInfo;
import com.linecorp.armeria.common.util.ThreadFactories;
import com.linecorp.armeria.common.util.TlsEngineType;
import com.linecorp.armeria.internal.common.BuiltInDependencyInjector;
import com.linecorp.armeria.internal.common.ReflectiveDependencyInjector;
import com.linecorp.armeria.internal.common.RequestContextUtil;
Expand Down Expand Up @@ -2181,7 +2182,7 @@ private DefaultServerConfig buildServerConfig(List<ServerPort> serverPorts) {
ports = ImmutableList.of(new ServerPort(0, HTTP));
}
} else {
if (!Flags.useOpenSsl() && !SystemInfo.jettyAlpnOptionalOrAvailable()) {
if (Flags.tlsEngineType() != TlsEngineType.OPENSSL && !SystemInfo.jettyAlpnOptionalOrAvailable()) {
throw new IllegalStateException(
"TLS configured but this is Java 8 and neither OpenSSL nor Jetty ALPN could be " +
"detected. To use TLS with Armeria, you must either use Java 9+, enable OpenSSL, " +
Expand Down
Loading

0 comments on commit 33ab3bb

Please sign in to comment.