From 7d4384c09d438e52f68f97d8d8d064e794e4d62d Mon Sep 17 00:00:00 2001 From: Eric Gribkoff Date: Fri, 23 Feb 2018 14:18:21 -0800 Subject: [PATCH 1/3] alts,interop-testing: build on JDK9 --- .../transportsecurity/AesGcmHkdfAeadCrypterTest.java | 12 ++++++------ .../java/io/grpc/ChannelAndServerBuilderTest.java | 12 ++++++++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/alts/src/test/java/io/grpc/alts/transportsecurity/AesGcmHkdfAeadCrypterTest.java b/alts/src/test/java/io/grpc/alts/transportsecurity/AesGcmHkdfAeadCrypterTest.java index 8819a3ffbc5..5c273cf59bf 100644 --- a/alts/src/test/java/io/grpc/alts/transportsecurity/AesGcmHkdfAeadCrypterTest.java +++ b/alts/src/test/java/io/grpc/alts/transportsecurity/AesGcmHkdfAeadCrypterTest.java @@ -18,10 +18,10 @@ import static com.google.common.truth.Truth.assertWithMessage; +import com.google.common.io.BaseEncoding; import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import java.util.Arrays; -import javax.xml.bind.DatatypeConverter; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -78,27 +78,27 @@ TestVectorBuilder withComment(String comment) { } TestVectorBuilder withKey(String key) { - this.key = DatatypeConverter.parseHexBinary(key); + this.key = BaseEncoding.base16().lowerCase().decode(key); return this; } TestVectorBuilder withNonce(String nonce) { - this.nonce = DatatypeConverter.parseHexBinary(nonce); + this.nonce = BaseEncoding.base16().lowerCase().decode(nonce); return this; } TestVectorBuilder withAad(String aad) { - this.aad = DatatypeConverter.parseHexBinary(aad); + this.aad = BaseEncoding.base16().lowerCase().decode(aad); return this; } TestVectorBuilder withPlaintext(String plaintext) { - this.plaintext = DatatypeConverter.parseHexBinary(plaintext); + this.plaintext = BaseEncoding.base16().lowerCase().decode(plaintext); return this; } TestVectorBuilder withCiphertext(String ciphertext) { - this.ciphertext = DatatypeConverter.parseHexBinary(ciphertext); + this.ciphertext = BaseEncoding.base16().lowerCase().decode(ciphertext); return this; } } diff --git a/interop-testing/src/test/java/io/grpc/ChannelAndServerBuilderTest.java b/interop-testing/src/test/java/io/grpc/ChannelAndServerBuilderTest.java index ac830b98485..15c91d1d136 100644 --- a/interop-testing/src/test/java/io/grpc/ChannelAndServerBuilderTest.java +++ b/interop-testing/src/test/java/io/grpc/ChannelAndServerBuilderTest.java @@ -36,6 +36,8 @@ /** * Tests that Channel and Server builders properly hide the static constructors. + * + *

This test does nothing on Java 9. */ @RunWith(Parameterized.class) public class ChannelAndServerBuilderTest { @@ -49,13 +51,19 @@ public class ChannelAndServerBuilderTest { @Parameters(name = "class={0}") public static Collection params() throws Exception { ClassLoader loader = ChannelAndServerBuilderTest.class.getClassLoader(); + Collection classInfos = + ClassPath.from(loader).getTopLevelClassesRecursive("io.grpc"); + // Java 9 doesn't expose the URLClassLoader, which breaks searching through the classpath + if (classInfos.isEmpty()) { + return new ArrayList(); + } List classes = new ArrayList(); - for (ClassInfo classInfo : ClassPath.from(loader).getTopLevelClassesRecursive("io.grpc")) { + for (ClassInfo classInfo : classInfos) { Class clazz = Class.forName(classInfo.getName(), false /*initialize*/, loader); if (ServerBuilder.class.isAssignableFrom(clazz) && clazz != ServerBuilder.class) { classes.add(new Object[]{clazz}); } else if (ManagedChannelBuilder.class.isAssignableFrom(clazz) - && clazz != ManagedChannelBuilder.class ) { + && clazz != ManagedChannelBuilder.class) { classes.add(new Object[]{clazz}); } } From 151c0e6ac3c5188182b30a357909ee70c986fb03 Mon Sep 17 00:00:00 2001 From: Eric Gribkoff Date: Fri, 23 Feb 2018 14:18:36 -0800 Subject: [PATCH 2/3] okhttp: support JDK9 ALPN --- .../okhttp/OkHttpProtocolNegotiatorTest.java | 4 + .../io/grpc/okhttp/internal/Platform.java | 79 ++++++++++++++++++- 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java b/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java index 2ac31ea51f5..66ee8c78de8 100644 --- a/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java +++ b/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java @@ -19,6 +19,7 @@ import static com.google.common.base.Charsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -32,6 +33,7 @@ import io.grpc.okhttp.internal.Protocol; import java.io.IOException; import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import org.junit.Rule; @@ -110,7 +112,9 @@ public void negotiatorNotNull() { @Test public void negotiate_handshakeFails() throws IOException { + SSLParameters parameters = mock(SSLParameters.class); OkHttpProtocolNegotiator negotiator = OkHttpProtocolNegotiator.get(); + doReturn(parameters).when(sock).getSSLParameters(); doThrow(new IOException()).when(sock).startHandshake(); thrown.expect(IOException.class); diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java index fb040d01a4e..7ddd7d53e8c 100644 --- a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java @@ -29,7 +29,10 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketException; +import java.security.AccessController; import java.security.NoSuchAlgorithmException; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.security.Provider; import java.security.Security; import java.util.ArrayList; @@ -37,6 +40,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocket; import okio.Buffer; @@ -44,19 +48,25 @@ * Access to platform-specific features. * *

Server name indication (SNI)

+ * * Supported on Android 2.3+. * *

Session Tickets

+ * * Supported on Android 2.3+. * *

Android Traffic Stats (Socket Tagging)

+ * * Supported on Android 4.0+. * *

ALPN (Application Layer Protocol Negotiation)

+ * * Supported on Android 5.0+. The APIs were present in Android 4.4, but that implementation was * unstable. * - * Supported on OpenJDK 7 and 8 (via the JettyALPN-boot library). + *

Supported on OpenJDK 9+. + * + *

Supported on OpenJDK 7 and 8 (via the JettyALPN-boot library). */ public class Platform { public static final Logger logger = Logger.getLogger(Platform.class.getName()); @@ -199,6 +209,23 @@ private static Platform findPlatform() { throw new RuntimeException(nsae); } + // Find JDK9+ ALPN support + try { + Method setApplicationProtocols = + SSLParameters.class.getMethod("setApplicationProtocols", String[].class); + Method getApplicationProtocol = + AccessController.doPrivileged( + new PrivilegedExceptionAction() { + @Override + public Method run() throws Exception { + return SSLSocket.class.getMethod("getApplicationProtocol"); + } + }); + return new JdkAlpnPlatform(sslProvider, setApplicationProtocols, getApplicationProtocol); + } catch (NoSuchMethodException ignored) { + } catch (PrivilegedActionException ignored) { + } + // Find Jetty's ALPN extension for OpenJDK. try { String negoClassName = "org.eclipse.jetty.alpn.ALPN"; @@ -375,6 +402,56 @@ public TlsExtensionType getTlsExtensionType() { } } + /** OpenJDK 9+. */ + private static class JdkAlpnPlatform extends Platform { + private final Method setApplicationProtocols; + private final Method getApplicationProtocol; + + private JdkAlpnPlatform( + Provider provider, Method setApplicationProtocols, Method getApplicationProtocol) { + super(provider); + this.setApplicationProtocols = setApplicationProtocols; + this.getApplicationProtocol = getApplicationProtocol; + } + + @Override + public TlsExtensionType getTlsExtensionType() { + return TlsExtensionType.ALPN_AND_NPN; + } + + @Override + public void configureTlsExtensions( + SSLSocket sslSocket, String hostname, List protocols) { + SSLParameters parameters = sslSocket.getSSLParameters(); + List names = new ArrayList(protocols.size()); + for (Protocol protocol : protocols) { + if (protocol == Protocol.HTTP_1_0) continue; // No HTTP/1.0 for ALPN. + names.add(protocol.toString()); + } + try { + setApplicationProtocols.invoke( + parameters, new Object[] {names.toArray(new String[names.size()])}); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + sslSocket.setSSLParameters(parameters); + } + + /** Returns the negotiated protocol, or null if no protocol was negotiated. */ + @Override + public String getSelectedProtocol(SSLSocket socket) { + try { + return (String) getApplicationProtocol.invoke(socket); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + } + /** * OpenJDK 7+ with {@code org.mortbay.jetty.alpn/alpn-boot} in the boot class path. */ From e9316f40c3e840f6e8ab8f3342fa2d42b1790447 Mon Sep 17 00:00:00 2001 From: Eric Gribkoff Date: Tue, 13 Mar 2018 14:56:57 -0700 Subject: [PATCH 3/3] verify getApplicationProtocol is supported --- .../okhttp/OkHttpProtocolNegotiatorTest.java | 2 +- .../io/grpc/okhttp/internal/Platform.java | 30 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java b/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java index 66ee8c78de8..4e836eec541 100644 --- a/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java +++ b/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java @@ -112,7 +112,7 @@ public void negotiatorNotNull() { @Test public void negotiate_handshakeFails() throws IOException { - SSLParameters parameters = mock(SSLParameters.class); + SSLParameters parameters = new SSLParameters(); OkHttpProtocolNegotiator negotiator = OkHttpProtocolNegotiator.get(); doReturn(parameters).when(sock).getSSLParameters(); doThrow(new IOException()).when(sock).startHandshake(); diff --git a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java index 7ddd7d53e8c..d6f88ba0e95 100644 --- a/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java +++ b/okhttp/third_party/okhttp/java/io/grpc/okhttp/internal/Platform.java @@ -30,6 +30,7 @@ import java.net.Socket; import java.net.SocketException; import java.security.AccessController; +import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; @@ -40,6 +41,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocket; import okio.Buffer; @@ -211,8 +213,29 @@ private static Platform findPlatform() { // Find JDK9+ ALPN support try { + // getApplicationProtocol() may throw UnsupportedOperationException, so first construct a + // dummy SSLEngine and verify the method does not throw. + SSLContext context = SSLContext.getInstance("TLS", sslProvider); + context.init(null, null, null); + SSLEngine engine = context.createSSLEngine(); + Method getEngineApplicationProtocol = + AccessController.doPrivileged( + new PrivilegedExceptionAction() { + @Override + public Method run() throws Exception { + return SSLEngine.class.getMethod("getApplicationProtocol"); + } + }); + getEngineApplicationProtocol.invoke(engine); + Method setApplicationProtocols = - SSLParameters.class.getMethod("setApplicationProtocols", String[].class); + AccessController.doPrivileged( + new PrivilegedExceptionAction() { + @Override + public Method run() throws Exception { + return SSLParameters.class.getMethod("setApplicationProtocols", String[].class); + } + }); Method getApplicationProtocol = AccessController.doPrivileged( new PrivilegedExceptionAction() { @@ -222,8 +245,11 @@ public Method run() throws Exception { } }); return new JdkAlpnPlatform(sslProvider, setApplicationProtocols, getApplicationProtocol); - } catch (NoSuchMethodException ignored) { + } catch (NoSuchAlgorithmException ignored) { + } catch (KeyManagementException ignored) { } catch (PrivilegedActionException ignored) { + } catch (IllegalAccessException ignored) { + } catch (InvocationTargetException ignored) { } // Find Jetty's ALPN extension for OpenJDK.