aboutsummaryrefslogtreecommitdiff
path: root/netty
diff options
context:
space:
mode:
authorEric Anderson <ejona@google.com>2018-02-15 17:14:10 -0800
committerEric Anderson <ejona@google.com>2018-03-23 10:05:45 -0700
commit7eab0d9468ae55bd2b443ae7738f9b8c03f43f26 (patch)
treeb0a908ec379ddc6b6956a0bc1cb53b9770c9782a /netty
parent0859d480e7c1498f811778d36114d9233345926a (diff)
downloadgrpc-grpc-java-7eab0d9468ae55bd2b443ae7738f9b8c03f43f26.tar.gz
netty: Add support for Conscrypt
Diffstat (limited to 'netty')
-rw-r--r--netty/build.gradle3
-rw-r--r--netty/src/main/java/io/grpc/netty/GrpcSslContexts.java155
-rw-r--r--netty/src/test/java/io/grpc/netty/TlsTest.java64
3 files changed, 175 insertions, 47 deletions
diff --git a/netty/build.gradle b/netty/build.gradle
index dcbffdadc..cc10105fc 100644
--- a/netty/build.gradle
+++ b/netty/build.gradle
@@ -8,7 +8,8 @@ dependencies {
testCompile project(':grpc-core').sourceSets.test.output,
project(':grpc-testing'),
project(':grpc-testing-proto')
- testRuntime libraries.netty_tcnative
+ testRuntime libraries.netty_tcnative,
+ libraries.conscrypt
signature "org.codehaus.mojo.signature:java17:1.0@signature"
}
diff --git a/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java b/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java
index 4c67ac4eb..15dfb63b9 100644
--- a/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java
+++ b/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java
@@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import io.grpc.ExperimentalApi;
+import io.grpc.internal.MoreThrowables;
import io.netty.handler.codec.http2.Http2SecurityUtil;
import io.netty.handler.ssl.ApplicationProtocolConfig;
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
@@ -30,9 +31,15 @@ import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.Provider;
+import java.security.Security;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
* Utility for configuring SslContext for gRPC.
@@ -40,6 +47,8 @@ import java.util.List;
@SuppressWarnings("deprecation")
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1784")
public class GrpcSslContexts {
+ private static final Logger logger = Logger.getLogger(GrpcSslContexts.class.getName());
+
private GrpcSslContexts() {}
/*
@@ -84,6 +93,22 @@ public class GrpcSslContexts {
SelectedListenerFailureBehavior.ACCEPT,
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 a SslContextBuilder with ciphers and APN appropriate for gRPC.
*
@@ -131,49 +156,115 @@ public class GrpcSslContexts {
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1784")
@CanIgnoreReturnValue
public static SslContextBuilder configure(SslContextBuilder builder, SslProvider provider) {
- return builder.sslProvider(provider)
- .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
- .applicationProtocolConfig(selectApplicationProtocolConfig(provider));
+ switch (provider) {
+ case JDK:
+ {
+ Provider jdkProvider = findJdkProvider();
+ if (jdkProvider == null) {
+ throw new IllegalArgumentException(
+ "Could not find Jetty NPN/ALPN or Conscrypt as installed JDK providers");
+ }
+ return configure(builder, jdkProvider);
+ }
+ case OPENSSL:
+ {
+ ApplicationProtocolConfig apc;
+ if (OpenSsl.isAlpnSupported()) {
+ apc = NPN_AND_ALPN;
+ } else {
+ apc = NPN;
+ }
+ return builder
+ .sslProvider(SslProvider.OPENSSL)
+ .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
+ .applicationProtocolConfig(apc);
+ }
+ default:
+ throw new IllegalArgumentException("Unsupported provider: " + provider);
+ }
}
/**
- * Returns OpenSSL if available, otherwise returns the JDK provider.
+ * Set ciphers and APN appropriate for gRPC. Precisely what is set is permitted to change, so if
+ * an application requires particular settings it should override the options set here.
*/
- private static SslProvider defaultSslProvider() {
- return OpenSsl.isAvailable() ? SslProvider.OPENSSL : SslProvider.JDK;
+ @CanIgnoreReturnValue
+ public static SslContextBuilder configure(SslContextBuilder builder, Provider jdkProvider) {
+ ApplicationProtocolConfig apc;
+ if (SUN_PROVIDER_NAME.equals(jdkProvider.getName())) {
+ // Jetty ALPN/NPN only supports one of NPN or ALPN
+ if (JettyTlsUtil.isJettyAlpnConfigured()) {
+ apc = ALPN;
+ } else if (JettyTlsUtil.isJettyNpnConfigured()) {
+ apc = NPN;
+ } else {
+ throw new IllegalArgumentException(
+ SUN_PROVIDER_NAME + " selected, but Jetty NPN/ALPN unavailable");
+ }
+ } else if (isConscrypt(jdkProvider)) {
+ apc = ALPN;
+ } else {
+ throw new IllegalArgumentException("Unknown provider; can't configure: " + jdkProvider);
+ }
+ return builder
+ .sslProvider(SslProvider.JDK)
+ .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
+ .applicationProtocolConfig(apc)
+ .sslContextProvider(jdkProvider);
}
/**
- * Attempts to select the best {@link ApplicationProtocolConfig} for the given
- * {@link SslProvider}.
+ * Returns OpenSSL if available, otherwise returns the JDK provider.
*/
- private static ApplicationProtocolConfig selectApplicationProtocolConfig(SslProvider provider) {
- switch (provider) {
- case JDK: {
- if (JettyTlsUtil.isJettyAlpnConfigured()) {
- return ALPN;
- }
- if (JettyTlsUtil.isJettyNpnConfigured()) {
- return NPN;
- }
- if (JettyTlsUtil.isJava9AlpnAvailable()) {
- return ALPN;
+ private static SslProvider defaultSslProvider() {
+ if (OpenSsl.isAvailable()) {
+ logger.log(Level.FINE, "Selecting OPENSSL");
+ return SslProvider.OPENSSL;
+ }
+ Provider provider = findJdkProvider();
+ if (provider != null) {
+ logger.log(Level.FINE, "Selecting JDK with provider {0}", provider);
+ return SslProvider.JDK;
+ }
+ 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, "Jetty ALPN unavailable (this may be normal)",
+ JettyTlsUtil.getJettyAlpnUnavailabilityCause());
+ throw new IllegalStateException(
+ "Could not find TLS ALPN provider; "
+ + "no working netty-tcnative, Conscrypt, or Jetty NPN/ALPN available");
+ }
+
+ private static Provider findJdkProvider() {
+ for (Provider provider : Security.getProviders("SSLContext.TLS")) {
+ if (SUN_PROVIDER_NAME.equals(provider.getName())) {
+ if (JettyTlsUtil.isJettyAlpnConfigured()
+ || JettyTlsUtil.isJettyNpnConfigured()
+ || JettyTlsUtil.isJava9AlpnAvailable()) {
+ return provider;
}
- // Use the ALPN cause since it is prefered.
- throw new IllegalArgumentException(
- "ALPN is not configured properly. See https://github.com/grpc/grpc-java/blob/master/SECURITY.md#troubleshooting"
- + " for more information.",
- JettyTlsUtil.getJettyAlpnUnavailabilityCause());
+ } else if (isConscrypt(provider)) {
+ return provider;
}
- case OPENSSL: {
- if (!OpenSsl.isAvailable()) {
- throw new IllegalArgumentException(
- "OpenSSL is not installed on the system.", OpenSsl.unavailabilityCause());
- }
- return OpenSsl.isAlpnSupported() ? NPN_AND_ALPN : NPN;
+ }
+ 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) {
+ MoreThrowables.throwIfUnchecked(ex.getCause());
+ // If checked, just wrap up everything.
}
- default:
- throw new IllegalArgumentException("Unsupported provider: " + provider);
+ throw new AssertionError(ex);
}
}
diff --git a/netty/src/test/java/io/grpc/netty/TlsTest.java b/netty/src/test/java/io/grpc/netty/TlsTest.java
index 3ee2ba5c1..c99d7f1ce 100644
--- a/netty/src/test/java/io/grpc/netty/TlsTest.java
+++ b/netty/src/test/java/io/grpc/netty/TlsTest.java
@@ -39,6 +39,8 @@ import io.netty.handler.ssl.SslProvider;
import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.concurrent.Executors;
@@ -48,6 +50,7 @@ import javax.net.ssl.SSLContext;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -61,41 +64,70 @@ import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class TlsTest {
+ public static enum TlsImpl {
+ TCNATIVE, JETTY, CONSCRYPT;
+ }
+
/**
* Iterable of various configurations to use for tests.
*/
@Parameters(name = "{0}")
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][] {
- {SslProvider.JDK}, {SslProvider.OPENSSL},
+ {TlsImpl.TCNATIVE}, {TlsImpl.JETTY}, {TlsImpl.CONSCRYPT},
});
}
@Parameter(value = 0)
- public SslProvider sslProvider;
+ public TlsImpl tlsImpl;
private ScheduledExecutorService executor;
private Server server;
private ManagedChannel channel;
+ private SslProvider sslProvider;
+ private Provider jdkProvider;
private SslContextBuilder clientContextBuilder;
+ @BeforeClass
+ public static void loadConscrypt() {
+ TestUtils.installConscryptIfAvailable();
+ }
+
@Before
public void setUp() throws NoSuchAlgorithmException {
executor = Executors.newSingleThreadScheduledExecutor();
- if (sslProvider == SslProvider.OPENSSL) {
- Assume.assumeTrue(OpenSsl.isAvailable());
+ switch (tlsImpl) {
+ case TCNATIVE:
+ Assume.assumeTrue(OpenSsl.isAvailable());
+ sslProvider = SslProvider.OPENSSL;
+ break;
+ case JETTY:
+ Assume.assumeTrue(Arrays.asList(
+ SSLContext.getDefault().getSupportedSSLParameters().getCipherSuites())
+ .contains("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"));
+ sslProvider = SslProvider.JDK;
+ jdkProvider = Security.getProvider("SunJSSE");
+ Assume.assumeNotNull(jdkProvider);
+ try {
+ GrpcSslContexts.configure(SslContextBuilder.forClient(), jdkProvider);
+ } catch (IllegalArgumentException ex) {
+ Assume.assumeNoException("Jetty ALPN does not seem available", ex);
+ }
+ break;
+ case CONSCRYPT:
+ sslProvider = SslProvider.JDK;
+ jdkProvider = Security.getProvider("Conscrypt");
+ Assume.assumeNotNull(jdkProvider);
+ break;
+ default:
+ throw new AssertionError();
}
+ clientContextBuilder = SslContextBuilder.forClient();
if (sslProvider == SslProvider.JDK) {
- Assume.assumeTrue(Arrays.asList(
- SSLContext.getDefault().getSupportedSSLParameters().getCipherSuites())
- .contains("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"));
- try {
- GrpcSslContexts.configure(SslContextBuilder.forClient(), SslProvider.JDK);
- } catch (IllegalArgumentException ex) {
- Assume.assumeNoException("Jetty ALPN does not seem available", ex);
- }
+ GrpcSslContexts.configure(clientContextBuilder, jdkProvider);
+ } else {
+ GrpcSslContexts.configure(clientContextBuilder, sslProvider);
}
- clientContextBuilder = GrpcSslContexts.configure(SslContextBuilder.forClient(), sslProvider);
}
@After
@@ -281,7 +313,11 @@ public class TlsTest {
File serverPrivateKeyFile, X509Certificate[] serverTrustedCaCerts) throws IOException {
SslContextBuilder sslContextBuilder
= SslContextBuilder.forServer(serverCertChainFile, serverPrivateKeyFile);
- GrpcSslContexts.configure(sslContextBuilder, sslProvider);
+ if (sslProvider == SslProvider.JDK) {
+ GrpcSslContexts.configure(sslContextBuilder, jdkProvider);
+ } else {
+ GrpcSslContexts.configure(sslContextBuilder, sslProvider);
+ }
sslContextBuilder.trustManager(serverTrustedCaCerts)
.clientAuth(ClientAuth.REQUIRE);