diff --git a/alts/src/test/java/io/grpc/alts/internal/AesGcmHkdfAeadCrypterTest.java b/alts/src/test/java/io/grpc/alts/internal/AesGcmHkdfAeadCrypterTest.java index be69cbd4456..ef64633ea5d 100644 --- a/alts/src/test/java/io/grpc/alts/internal/AesGcmHkdfAeadCrypterTest.java +++ b/alts/src/test/java/io/grpc/alts/internal/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}); } } diff --git a/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java b/okhttp/src/test/java/io/grpc/okhttp/OkHttpProtocolNegotiatorTest.java index 2ac31ea51f5..4e836eec541 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 = new SSLParameters(); 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..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 @@ -29,7 +29,11 @@ import java.net.InetSocketAddress; 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; import java.security.Provider; import java.security.Security; import java.util.ArrayList; @@ -37,6 +41,8 @@ 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; @@ -44,19 +50,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 +211,47 @@ private static Platform findPlatform() { throw new RuntimeException(nsae); } + // 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 = + AccessController.doPrivileged( + new PrivilegedExceptionAction() { + @Override + public Method run() throws Exception { + return 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 (NoSuchAlgorithmException ignored) { + } catch (KeyManagementException ignored) { + } catch (PrivilegedActionException ignored) { + } catch (IllegalAccessException ignored) { + } catch (InvocationTargetException ignored) { + } + // Find Jetty's ALPN extension for OpenJDK. try { String negoClassName = "org.eclipse.jetty.alpn.ALPN"; @@ -375,6 +428,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. */