Skip to content

Commit

Permalink
netty: Implicitly enable Conscrypt when it is available
Browse files Browse the repository at this point in the history
This implicit loading is more conservative than the loading for
tcnative, as Conscrypt will only be implicitly loaded if there are no
other options. This means the Java 9+ JSSE is preferred over Conscrypt
without explicit user configuration.

While we would generally prefer Conscrypt over JSSE, we want to allow
the user to configure their security providers. There wasn't a good way
to do that with netty-tcnative and the performance of JSSE at the time
was abysmal.

While generally being a good way to allow adopting Conscrypt, this also
allows easily using App Engine Java 8's provided Conscrypt which can
substantially reduce binary size.

See googleapis/google-cloud-java#6425
  • Loading branch information
ejona86 committed Oct 7, 2019
1 parent e9921b7 commit 2caa77d
Showing 1 changed file with 29 additions and 38 deletions.
67 changes: 29 additions & 38 deletions netty/src/main/java/io/grpc/netty/GrpcSslContexts.java
Expand Up @@ -18,9 +18,9 @@

import static com.google.common.base.Preconditions.checkArgument;

import com.google.common.base.Throwables;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import io.grpc.ExperimentalApi;
import io.grpc.internal.ConscryptLoader;
import io.netty.handler.codec.http2.Http2SecurityUtil;
import io.netty.handler.ssl.ApplicationProtocolConfig;
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
Expand All @@ -32,8 +32,6 @@
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.Provider;
import java.security.Security;
import java.util.Arrays;
Expand Down Expand Up @@ -95,20 +93,6 @@ private GrpcSslContexts() {}
NEXT_PROTOCOL_VERSIONS);

private static final String SUN_PROVIDER_NAME = "SunJSSE";
private static final Method IS_CONSCRYPT_PROVIDER;

static {
Method method = null;
try {
Class<?> conscryptClass = Class.forName("org.conscrypt.Conscrypt");
method = conscryptClass.getMethod("isConscrypt", Provider.class);
} catch (ClassNotFoundException ex) {
logger.log(Level.FINE, "Conscrypt class not found. Not using Conscrypt", ex);
} catch (NoSuchMethodException ex) {
throw new AssertionError(ex);
}
IS_CONSCRYPT_PROVIDER = method;
}

/**
* Creates an SslContextBuilder with ciphers and APN appropriate for gRPC.
Expand Down Expand Up @@ -223,9 +207,9 @@ public static SslContextBuilder configure(SslContextBuilder builder, Provider jd
apc = ALPN;
} else {
throw new IllegalArgumentException(
SUN_PROVIDER_NAME + " selected, but Jetty NPN/ALPN unavailable");
SUN_PROVIDER_NAME + " selected, but Java 9+ and Jetty NPN/ALPN unavailable");
}
} else if (isConscrypt(jdkProvider)) {
} else if (ConscryptLoader.isConscrypt(jdkProvider)) {
apc = ALPN;
} else {
throw new IllegalArgumentException("Unknown provider; can't configure: " + jdkProvider);
Expand All @@ -250,9 +234,11 @@ private static SslProvider defaultSslProvider() {
logger.log(Level.FINE, "Selecting JDK with provider {0}", provider);
return SslProvider.JDK;
}
logger.log(Level.INFO, "Java 9 ALPN API unavailable (this may be normal)");
logger.log(Level.INFO, "netty-tcnative unavailable (this may be normal)",
OpenSsl.unavailabilityCause());
logger.log(Level.INFO, "Conscrypt not found (this may be normal)");
logger.log(Level.INFO, "Conscrypt not found (this may be normal)",
ConscryptHolder.UNAVAILABILITY_CAUSE);
logger.log(Level.INFO, "Jetty ALPN unavailable (this may be normal)",
JettyTlsUtil.getJettyAlpnUnavailabilityCause());
throw new IllegalStateException(
Expand All @@ -268,28 +254,14 @@ private static Provider findJdkProvider() {
|| JettyTlsUtil.isJava9AlpnAvailable()) {
return provider;
}
} else if (isConscrypt(provider)) {
} else if (ConscryptLoader.isConscrypt(provider)) {
return provider;
}
}
return null;
}

private static boolean isConscrypt(Provider provider) {
if (IS_CONSCRYPT_PROVIDER == null) {
return false;
}
try {
return (Boolean) IS_CONSCRYPT_PROVIDER.invoke(null, provider);
} catch (IllegalAccessException ex) {
throw new AssertionError(ex);
} catch (InvocationTargetException ex) {
if (ex.getCause() != null) {
Throwables.throwIfUnchecked(ex.getCause());
// If checked, just wrap up everything.
}
throw new AssertionError(ex);
if (ConscryptHolder.PROVIDER != null) {
return ConscryptHolder.PROVIDER;
}
return null;
}

@SuppressWarnings("deprecation")
Expand All @@ -304,4 +276,23 @@ static void ensureAlpnAndH2Enabled(
HTTP2_VERSION,
alpnNegotiator.protocols());
}

private static class ConscryptHolder {
static final Provider PROVIDER;
static final Throwable UNAVAILABILITY_CAUSE;

static {
Provider provider;
Throwable cause;
try {
provider = ConscryptLoader.newProvider();
cause = null;
} catch (Throwable t) {
provider = null;
cause = t;
}
PROVIDER = provider;
UNAVAILABILITY_CAUSE = cause;
}
}
}

0 comments on commit 2caa77d

Please sign in to comment.