From 0d64fc350f0aedd106b4d1a464c6034b116c41da Mon Sep 17 00:00:00 2001 From: Spencer Fang Date: Fri, 6 Apr 2018 16:07:18 -0700 Subject: [PATCH 1/3] core, netty: allow InputStream based certs Allow ServerBuilder to read certs from InputStream, not just from a File. --- core/src/main/java/io/grpc/ServerBuilder.java | 17 +++++ .../java/io/grpc/netty/GrpcSslContexts.java | 22 +++++++ .../io/grpc/netty/NettyServerBuilder.java | 12 ++++ .../src/test/java/io/grpc/netty/TlsTest.java | 66 +++++++++++++++++++ 4 files changed, 117 insertions(+) diff --git a/core/src/main/java/io/grpc/ServerBuilder.java b/core/src/main/java/io/grpc/ServerBuilder.java index 5d6e4f18161..397010be8c1 100644 --- a/core/src/main/java/io/grpc/ServerBuilder.java +++ b/core/src/main/java/io/grpc/ServerBuilder.java @@ -17,6 +17,7 @@ package io.grpc; import java.io.File; +import java.io.InputStream; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; @@ -150,6 +151,22 @@ public T addStreamTracerFactory(ServerStreamTracer.Factory factory) { */ public abstract T useTransportSecurity(File certChain, File privateKey); + /** + * Makes the server use TLS. + * + * @param certChain InputStream containing the full certificate chain + * @param privateKey InputStream containing the private key + * + * @return this + * @throws UnsupportedOperationException if the server does not support TLS, or does not support + * reading these files from an InputStream. + * @since 1.12.0 + */ + public T useTransportSecurity(InputStream certChain, InputStream privateKey) { + throw new UnsupportedOperationException(); + } + + /** * Set the decompression registry for use in the channel. This is an advanced API call and * shouldn't be used unless you are using custom message encoding. The default supported diff --git a/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java b/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java index 15dfb63b963..07b1a9a22fd 100644 --- a/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java +++ b/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java @@ -31,6 +31,7 @@ import io.netty.handler.ssl.SslProvider; 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; @@ -140,6 +141,27 @@ public static SslContextBuilder forServer( return configure(SslContextBuilder.forServer(keyCertChainFile, keyFile, keyPassword)); } + /** + * Creates a SslContextBuilder with ciphers and APN appropriate for gRPC. + * + * @see SslContextBuilder#forServer(InputStream, InputStream) + * @see #configure(SslContextBuilder) + */ + public static SslContextBuilder forServer(InputStream keyCertChain, InputStream key) { + return configure(SslContextBuilder.forServer(keyCertChain, key)); + } + + /** + * Creates a SslContextBuilder with ciphers and APN appropriate for gRPC. + * + * @see SslContextBuilder#forServer(InputStream, InputStream, String) + * @see #configure(SslContextBuilder) + */ + public static SslContextBuilder forServer( + InputStream keyCertChain, InputStream key, String keyPassword) { + return configure(SslContextBuilder.forServer(keyCertChain, key, keyPassword)); + } + /** * 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. diff --git a/netty/src/main/java/io/grpc/netty/NettyServerBuilder.java b/netty/src/main/java/io/grpc/netty/NettyServerBuilder.java index 4e7df63805e..ae7463ff763 100644 --- a/netty/src/main/java/io/grpc/netty/NettyServerBuilder.java +++ b/netty/src/main/java/io/grpc/netty/NettyServerBuilder.java @@ -38,6 +38,7 @@ import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.ssl.SslContext; import java.io.File; +import java.io.InputStream; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.HashMap; @@ -438,4 +439,15 @@ public NettyServerBuilder useTransportSecurity(File certChain, File privateKey) } return this; } + + @Override + public NettyServerBuilder useTransportSecurity(InputStream certChain, InputStream privateKey) { + try { + sslContext = GrpcSslContexts.forServer(certChain, privateKey).build(); + } catch (SSLException e) { + // This should likely be some other, easier to catch exception. + throw new RuntimeException(e); + } + return this; + } } diff --git a/netty/src/test/java/io/grpc/netty/TlsTest.java b/netty/src/test/java/io/grpc/netty/TlsTest.java index c99d7f1ce1b..e620cfcf1ef 100644 --- a/netty/src/test/java/io/grpc/netty/TlsTest.java +++ b/netty/src/test/java/io/grpc/netty/TlsTest.java @@ -37,7 +37,9 @@ import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslProvider; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.Security; @@ -176,6 +178,70 @@ public void basicClientServerIntegrationTest() throws Exception { client.unaryRpc(SimpleRequest.getDefaultInstance()); } + /** + * Same as basicClientServerIntegrationTest except we test the InputStream based certs API. + */ + @Test + public void basicClientServerIntegrationTestInputStreamCerts() throws Exception { + InputStream serverCertChain = null; + InputStream serverPrivateKey = null; + InputStream clientCertChain = null; + InputStream clientPrivateKey = null; + + try { + // Create & start a server. + File serverCertChainFile = TestUtils.loadCert("server1.pem"); + File serverPrivateKeyFile = TestUtils.loadCert("server1.key"); + X509Certificate[] serverTrustedCaCerts = { + TestUtils.loadX509Cert("ca.pem") + }; + serverCertChain = new FileInputStream(serverCertChainFile); + serverPrivateKey = new FileInputStream(serverPrivateKeyFile); + SslContextBuilder sslContextBuilder + = SslContextBuilder.forServer(serverCertChain, serverPrivateKey); + GrpcSslContexts.configure(sslContextBuilder, sslProvider); + sslContextBuilder.trustManager(serverTrustedCaCerts) + .clientAuth(ClientAuth.REQUIRE); + server = NettyServerBuilder.forPort(0) + .sslContext(sslContextBuilder.build()) + .addService(new SimpleServiceImpl()) + .build() + .start(); + + // Create a client. + File clientCertChainFile = TestUtils.loadCert("client.pem"); + File clientPrivateKeyFile = TestUtils.loadCert("client.key"); + X509Certificate[] clientTrustedCaCerts = { + TestUtils.loadX509Cert("ca.pem") + }; + + clientCertChain = new FileInputStream(clientCertChainFile); + clientPrivateKey = new FileInputStream(clientPrivateKeyFile); + channel = clientChannel(server.getPort(), clientContextBuilder + .keyManager(clientCertChain, clientPrivateKey) + .trustManager(clientTrustedCaCerts) + .build()); + } finally { + if (serverCertChain != null) { + serverCertChain.close(); + } + if (serverPrivateKey != null) { + serverPrivateKey.close(); + } + if (clientCertChain != null) { + clientCertChain.close(); + } + if (clientPrivateKey != null) { + clientPrivateKey.close(); + } + } + + SimpleServiceGrpc.SimpleServiceBlockingStub client = SimpleServiceGrpc.newBlockingStub(channel); + + // Send an actual request, via the full GRPC & network stack, and check that a proper + // response comes back. + client.unaryRpc(SimpleRequest.getDefaultInstance()); + } /** * Tests that a server configured to require client authentication refuses to accept connections From 22830d91f64f84f7f102c35052da36172758df7e Mon Sep 17 00:00:00 2001 From: Spencer Fang Date: Tue, 10 Apr 2018 17:57:25 -0700 Subject: [PATCH 2/3] remove unneeded test --- .../src/test/java/io/grpc/netty/TlsTest.java | 65 ------------------- 1 file changed, 65 deletions(-) diff --git a/netty/src/test/java/io/grpc/netty/TlsTest.java b/netty/src/test/java/io/grpc/netty/TlsTest.java index e620cfcf1ef..efbbb2ae212 100644 --- a/netty/src/test/java/io/grpc/netty/TlsTest.java +++ b/netty/src/test/java/io/grpc/netty/TlsTest.java @@ -178,71 +178,6 @@ public void basicClientServerIntegrationTest() throws Exception { client.unaryRpc(SimpleRequest.getDefaultInstance()); } - /** - * Same as basicClientServerIntegrationTest except we test the InputStream based certs API. - */ - @Test - public void basicClientServerIntegrationTestInputStreamCerts() throws Exception { - InputStream serverCertChain = null; - InputStream serverPrivateKey = null; - InputStream clientCertChain = null; - InputStream clientPrivateKey = null; - - try { - // Create & start a server. - File serverCertChainFile = TestUtils.loadCert("server1.pem"); - File serverPrivateKeyFile = TestUtils.loadCert("server1.key"); - X509Certificate[] serverTrustedCaCerts = { - TestUtils.loadX509Cert("ca.pem") - }; - serverCertChain = new FileInputStream(serverCertChainFile); - serverPrivateKey = new FileInputStream(serverPrivateKeyFile); - SslContextBuilder sslContextBuilder - = SslContextBuilder.forServer(serverCertChain, serverPrivateKey); - GrpcSslContexts.configure(sslContextBuilder, sslProvider); - sslContextBuilder.trustManager(serverTrustedCaCerts) - .clientAuth(ClientAuth.REQUIRE); - server = NettyServerBuilder.forPort(0) - .sslContext(sslContextBuilder.build()) - .addService(new SimpleServiceImpl()) - .build() - .start(); - - // Create a client. - File clientCertChainFile = TestUtils.loadCert("client.pem"); - File clientPrivateKeyFile = TestUtils.loadCert("client.key"); - X509Certificate[] clientTrustedCaCerts = { - TestUtils.loadX509Cert("ca.pem") - }; - - clientCertChain = new FileInputStream(clientCertChainFile); - clientPrivateKey = new FileInputStream(clientPrivateKeyFile); - channel = clientChannel(server.getPort(), clientContextBuilder - .keyManager(clientCertChain, clientPrivateKey) - .trustManager(clientTrustedCaCerts) - .build()); - } finally { - if (serverCertChain != null) { - serverCertChain.close(); - } - if (serverPrivateKey != null) { - serverPrivateKey.close(); - } - if (clientCertChain != null) { - clientCertChain.close(); - } - if (clientPrivateKey != null) { - clientPrivateKey.close(); - } - } - - SimpleServiceGrpc.SimpleServiceBlockingStub client = SimpleServiceGrpc.newBlockingStub(channel); - - // Send an actual request, via the full GRPC & network stack, and check that a proper - // response comes back. - client.unaryRpc(SimpleRequest.getDefaultInstance()); - } - /** * Tests that a server configured to require client authentication refuses to accept connections * from a client that has an untrusted certificate. From 580d5771c37192dd59c64857c0720d4e8aeaa324 Mon Sep 17 00:00:00 2001 From: Spencer Fang Date: Wed, 11 Apr 2018 11:48:30 -0700 Subject: [PATCH 3/3] revert impotrs --- netty/src/test/java/io/grpc/netty/TlsTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/netty/src/test/java/io/grpc/netty/TlsTest.java b/netty/src/test/java/io/grpc/netty/TlsTest.java index efbbb2ae212..6628a39a646 100644 --- a/netty/src/test/java/io/grpc/netty/TlsTest.java +++ b/netty/src/test/java/io/grpc/netty/TlsTest.java @@ -37,9 +37,7 @@ import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslProvider; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.Security;