Skip to content

Commit be64ff4

Browse files
committed
core,netty: InputStream support in SslContextBuilder
Also update unit tests to stop writing certs to temp files. Fixes grpc#1881
1 parent 5bf4f5b commit be64ff4

File tree

15 files changed

+123
-90
lines changed

15 files changed

+123
-90
lines changed

benchmarks/src/main/java/io/grpc/benchmarks/Utils.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ private static NettyChannelBuilder newNettyClientChannel(Transport transport,
154154
builder.negotiationType(NegotiationType.TLS);
155155
SslContext sslContext = null;
156156
if (testca) {
157-
File cert = TestUtils.loadCert("ca.pem");
158-
SslContextBuilder sslContextBuilder = GrpcSslContexts.forClient().trustManager(cert);
157+
SslContextBuilder sslContextBuilder =
158+
GrpcSslContexts.forClient().trustManager(TestUtils.loadCert("ca.pem"));
159159
if (transport == Transport.NETTY_NIO) {
160160
sslContextBuilder = GrpcSslContexts.configure(sslContextBuilder, SslProvider.JDK);
161161
} else {

benchmarks/src/main/java/io/grpc/benchmarks/driver/LoadServer.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import io.grpc.internal.testing.TestUtils;
4040
import io.netty.buffer.ByteBuf;
4141
import io.netty.buffer.PooledByteBufAllocator;
42-
import java.io.File;
4342
import java.lang.management.ManagementFactory;
4443
import java.util.List;
4544
import java.util.concurrent.ExecutorService;
@@ -115,9 +114,8 @@ final class LoadServer {
115114
}
116115
}
117116
if (config.hasSecurityParams()) {
118-
File cert = TestUtils.loadCert("server1.pem");
119-
File key = TestUtils.loadCert("server1.key");
120-
serverBuilder.useTransportSecurity(cert, key);
117+
serverBuilder.useTransportSecurity(
118+
TestUtils.loadCert("server1.pem"), TestUtils.loadCert("server1.key"));
121119
}
122120
benchmarkService = new AsyncServer.BenchmarkServiceImpl();
123121
if (config.getServerType() == Control.ServerType.ASYNC_GENERIC_SERVER) {

benchmarks/src/main/java/io/grpc/benchmarks/qps/AsyncServer.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import io.netty.handler.ssl.SslContextBuilder;
3838
import io.netty.handler.ssl.SslProvider;
3939
import io.netty.util.concurrent.DefaultThreadFactory;
40-
import java.io.File;
4140
import java.io.IOException;
4241
import java.util.Iterator;
4342
import java.util.concurrent.ForkJoinPool;
@@ -99,9 +98,8 @@ static Server newServer(ServerConfiguration config) throws IOException {
9998
System.out.println("Using fake CA for TLS certificate.\n"
10099
+ "Run the Java client with --tls --testca");
101100

102-
File cert = TestUtils.loadCert("server1.pem");
103-
File key = TestUtils.loadCert("server1.key");
104-
SslContextBuilder sslContextBuilder = GrpcSslContexts.forServer(cert, key);
101+
SslContextBuilder sslContextBuilder = GrpcSslContexts.forServer(
102+
TestUtils.loadCert("server1.pem"), TestUtils.loadCert("server1.key"));
105103
if (config.transport == ServerConfiguration.Transport.NETTY_NIO) {
106104
sslContextBuilder = GrpcSslContexts.configure(sslContextBuilder, SslProvider.JDK);
107105
} else {

core/src/main/java/io/grpc/ServerBuilder.java

+13
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.grpc;
1818

1919
import java.io.File;
20+
import java.io.InputStream;
2021
import java.util.concurrent.Executor;
2122
import javax.annotation.Nullable;
2223

@@ -150,6 +151,18 @@ public T addStreamTracerFactory(ServerStreamTracer.Factory factory) {
150151
*/
151152
public abstract T useTransportSecurity(File certChain, File privateKey);
152153

154+
/**
155+
* Makes the server use TLS.
156+
*
157+
* @param certChain InputStream containing the full certificate chain
158+
* @param privateKey InputStream containing the private key
159+
*
160+
* @return this
161+
* @throws UnsupportedOperationException if the server does not support TLS.
162+
* @since 1.7.0
163+
*/
164+
public abstract T useTransportSecurity(InputStream certChain, InputStream privateKey);
165+
153166
/**
154167
* Set the decompression registry for use in the channel. This is an advanced API call and
155168
* shouldn't be used unless you are using custom message encoding. The default supported

core/src/main/java/io/grpc/inprocess/InProcessServerBuilder.java

+7
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.grpc.internal.AbstractServerImplBuilder;
2323
import io.grpc.internal.GrpcUtil;
2424
import java.io.File;
25+
import java.io.InputStream;
2526
import java.util.List;
2627

2728
/**
@@ -94,4 +95,10 @@ protected InProcessServer buildTransportServer(
9495
public InProcessServerBuilder useTransportSecurity(File certChain, File privateKey) {
9596
throw new UnsupportedOperationException("TLS not supported in InProcessServer");
9697
}
98+
99+
@Override
100+
public InProcessServerBuilder useTransportSecurity(
101+
InputStream certChain, InputStream privateKey) {
102+
throw new UnsupportedOperationException("TLS not supported in InProcessServer");
103+
}
97104
}

core/src/main/java/io/grpc/internal/GrpcUtil.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ static void closeQuietly(MessageProducer producer) {
624624
}
625625

626626
/** Closes an InputStream, ignoring IOExceptions. */
627-
static void closeQuietly(InputStream message) {
627+
public static void closeQuietly(InputStream message) {
628628
try {
629629
message.close();
630630
} catch (IOException ioException) {

core/src/test/java/io/grpc/internal/AbstractServerImplBuilderTest.java

+5
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ protected io.grpc.internal.InternalServer buildTransportServer(
110110
public Builder useTransportSecurity(File certChain, File privateKey) {
111111
throw new UnsupportedOperationException();
112112
}
113+
114+
@Override
115+
public Builder useTransportSecurity(InputStream certChain, InputStream privateKey) {
116+
throw new UnsupportedOperationException();
117+
}
113118
}
114119

115120
}

core/src/test/java/io/grpc/internal/ServerImplTest.java

+5
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,11 @@ private static class Builder extends AbstractServerImplBuilder<Builder> {
12481248
@Override public Builder useTransportSecurity(File f1, File f2) {
12491249
throw new UnsupportedOperationException();
12501250
}
1251+
1252+
@Override
1253+
public Builder useTransportSecurity(InputStream certChain, InputStream privateKey) {
1254+
throw new UnsupportedOperationException("TLS not supported in InProcessServer");
1255+
}
12511256
}
12521257

12531258
/** Allows more precise catch blocks than plain Error to avoid catching AssertionError. */

interop-testing/src/test/java/io/grpc/testing/integration/ConcurrencyTest.java

+9-12
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package io.grpc.testing.integration;
1818

19+
import static io.grpc.internal.testing.TestUtils.loadCert;
20+
1921
import com.google.common.base.Preconditions;
2022
import com.google.common.util.concurrent.MoreExecutors;
2123
import io.grpc.ManagedChannel;
@@ -32,7 +34,6 @@
3234
import io.grpc.testing.integration.Messages.StreamingOutputCallResponse;
3335
import io.netty.handler.ssl.ClientAuth;
3436
import io.netty.handler.ssl.SslContext;
35-
import java.io.File;
3637
import java.io.IOException;
3738
import java.security.cert.CertificateException;
3839
import java.security.cert.X509Certificate;
@@ -182,17 +183,15 @@ public void serverStreamingTest() throws Exception {
182183
* Creates and starts a new {@link TestServiceImpl} server.
183184
*/
184185
private Server newServer() throws CertificateException, IOException {
185-
File serverCertChainFile = TestUtils.loadCert("server1.pem");
186-
File serverPrivateKeyFile = TestUtils.loadCert("server1.key");
187186
X509Certificate[] serverTrustedCaCerts = {
188187
TestUtils.loadX509Cert("ca.pem")
189188
};
190189

191190
SslContext sslContext =
192-
GrpcSslContexts.forServer(serverCertChainFile, serverPrivateKeyFile)
193-
.trustManager(serverTrustedCaCerts)
194-
.clientAuth(ClientAuth.REQUIRE)
195-
.build();
191+
GrpcSslContexts.forServer(loadCert("server1.pem"), loadCert("server1.key"))
192+
.trustManager(serverTrustedCaCerts)
193+
.clientAuth(ClientAuth.REQUIRE)
194+
.build();
196195

197196
return NettyServerBuilder.forPort(0)
198197
.sslContext(sslContext)
@@ -202,17 +201,15 @@ private Server newServer() throws CertificateException, IOException {
202201
}
203202

204203
private ManagedChannel newClientChannel() throws CertificateException, IOException {
205-
File clientCertChainFile = TestUtils.loadCert("client.pem");
206-
File clientPrivateKeyFile = TestUtils.loadCert("client.key");
207204
X509Certificate[] clientTrustedCaCerts = {
208205
TestUtils.loadX509Cert("ca.pem")
209206
};
210207

211208
SslContext sslContext =
212209
GrpcSslContexts.forClient()
213-
.keyManager(clientCertChainFile, clientPrivateKeyFile)
214-
.trustManager(clientTrustedCaCerts)
215-
.build();
210+
.keyManager(loadCert("client.pem"), loadCert("client.key"))
211+
.trustManager(clientTrustedCaCerts)
212+
.build();
216213

217214
return NettyChannelBuilder.forAddress("localhost", server.getPort())
218215
.overrideAuthority(TestUtils.TEST_SERVER_HOST)

interop-testing/src/test/java/io/grpc/testing/integration/TlsTest.java

+21-28
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.grpc.testing.integration;
1818

19+
import static io.grpc.internal.testing.TestUtils.loadCert;
1920
import static org.junit.Assert.assertEquals;
2021
import static org.junit.Assert.fail;
2122

@@ -37,8 +38,8 @@
3738
import io.netty.handler.ssl.SslContext;
3839
import io.netty.handler.ssl.SslContextBuilder;
3940
import io.netty.handler.ssl.SslProvider;
40-
import java.io.File;
4141
import java.io.IOException;
42+
import java.io.InputStream;
4243
import java.security.NoSuchAlgorithmException;
4344
import java.security.cert.X509Certificate;
4445
import java.util.Arrays;
@@ -118,24 +119,21 @@ public void tearDown() {
118119
@Test
119120
public void basicClientServerIntegrationTest() throws Exception {
120121
// Create & start a server.
121-
File serverCertFile = TestUtils.loadCert("server1.pem");
122-
File serverPrivateKeyFile = TestUtils.loadCert("server1.key");
123122
X509Certificate[] serverTrustedCaCerts = {
124123
TestUtils.loadX509Cert("ca.pem")
125124
};
126-
server = serverBuilder(0, serverCertFile, serverPrivateKeyFile, serverTrustedCaCerts)
125+
server = serverBuilder(
126+
0, loadCert("server1.pem"), loadCert("server1.key"), serverTrustedCaCerts)
127127
.addService(new TestServiceImpl(executor))
128128
.build()
129129
.start();
130130

131131
// Create a client.
132-
File clientCertChainFile = TestUtils.loadCert("client.pem");
133-
File clientPrivateKeyFile = TestUtils.loadCert("client.key");
134132
X509Certificate[] clientTrustedCaCerts = {
135133
TestUtils.loadX509Cert("ca.pem")
136134
};
137135
channel = clientChannel(server.getPort(), clientContextBuilder
138-
.keyManager(clientCertChainFile, clientPrivateKeyFile)
136+
.keyManager(loadCert("client.pem"), loadCert("client.key"))
139137
.trustManager(clientTrustedCaCerts)
140138
.build());
141139
TestServiceGrpc.TestServiceBlockingStub client = TestServiceGrpc.newBlockingStub(channel);
@@ -154,26 +152,23 @@ public void basicClientServerIntegrationTest() throws Exception {
154152
@Test
155153
public void serverRejectsUntrustedClientCert() throws Exception {
156154
// Create & start a server. It requires client authentication and trusts only the test CA.
157-
File serverCertFile = TestUtils.loadCert("server1.pem");
158-
File serverPrivateKeyFile = TestUtils.loadCert("server1.key");
159155
X509Certificate[] serverTrustedCaCerts = {
160156
TestUtils.loadX509Cert("ca.pem")
161157
};
162-
server = serverBuilder(0, serverCertFile, serverPrivateKeyFile, serverTrustedCaCerts)
158+
server = serverBuilder(
159+
0, loadCert("server1.pem"), loadCert("server1.key"), serverTrustedCaCerts)
163160
.addService(new TestServiceImpl(executor))
164161
.build()
165162
.start();
166163

167164
// Create a client. Its credentials come from a CA that the server does not trust. The client
168165
// trusts both test CAs, so we can be sure that the handshake failure is due to the server
169166
// rejecting the client's cert, not the client rejecting the server's cert.
170-
File clientCertChainFile = TestUtils.loadCert("badclient.pem");
171-
File clientPrivateKeyFile = TestUtils.loadCert("badclient.key");
172167
X509Certificate[] clientTrustedCaCerts = {
173168
TestUtils.loadX509Cert("ca.pem")
174169
};
175170
channel = clientChannel(server.getPort(), clientContextBuilder
176-
.keyManager(clientCertChainFile, clientPrivateKeyFile)
171+
.keyManager(loadCert("badclient.pem"), loadCert("badclient.key"))
177172
.trustManager(clientTrustedCaCerts)
178173
.build());
179174
TestServiceGrpc.TestServiceBlockingStub client = TestServiceGrpc.newBlockingStub(channel);
@@ -201,12 +196,11 @@ public void serverRejectsUntrustedClientCert() throws Exception {
201196
@Test
202197
public void noClientAuthFailure() throws Exception {
203198
// Create & start a server.
204-
File serverCertFile = TestUtils.loadCert("server1.pem");
205-
File serverPrivateKeyFile = TestUtils.loadCert("server1.key");
206199
X509Certificate[] serverTrustedCaCerts = {
207200
TestUtils.loadX509Cert("ca.pem")
208201
};
209-
server = serverBuilder(0, serverCertFile, serverPrivateKeyFile, serverTrustedCaCerts)
202+
server = serverBuilder(
203+
0, loadCert("server1.pem"), loadCert("server1.key"), serverTrustedCaCerts)
210204
.addService(new TestServiceImpl(executor))
211205
.build()
212206
.start();
@@ -243,26 +237,25 @@ public void noClientAuthFailure() throws Exception {
243237
@Test
244238
public void clientRejectsUntrustedServerCert() throws Exception {
245239
// Create & start a server.
246-
File serverCertFile = TestUtils.loadCert("badserver.pem");
247-
File serverPrivateKeyFile = TestUtils.loadCert("badserver.key");
248240
X509Certificate[] serverTrustedCaCerts = {
249241
TestUtils.loadX509Cert("ca.pem")
250242
};
251-
server = serverBuilder(0, serverCertFile, serverPrivateKeyFile, serverTrustedCaCerts)
243+
server = serverBuilder(
244+
0, loadCert("badserver.pem"), loadCert("badserver.key"), serverTrustedCaCerts)
252245
.addService(new TestServiceImpl(executor))
253246
.build()
254247
.start();
255248

256249
// Create a client.
257-
File clientCertChainFile = TestUtils.loadCert("client.pem");
258-
File clientPrivateKeyFile = TestUtils.loadCert("client.key");
259250
X509Certificate[] clientTrustedCaCerts = {
260251
TestUtils.loadX509Cert("ca.pem")
261252
};
262-
channel = clientChannel(server.getPort(), clientContextBuilder
263-
.keyManager(clientCertChainFile, clientPrivateKeyFile)
264-
.trustManager(clientTrustedCaCerts)
265-
.build());
253+
channel =
254+
clientChannel(
255+
server.getPort(),
256+
clientContextBuilder.keyManager(loadCert("client.pem"), loadCert("client.key"))
257+
.trustManager(clientTrustedCaCerts)
258+
.build());
266259
TestServiceGrpc.TestServiceBlockingStub client = TestServiceGrpc.newBlockingStub(channel);
267260

268261
// Check that the TLS handshake fails.
@@ -282,10 +275,10 @@ public void clientRejectsUntrustedServerCert() throws Exception {
282275
}
283276

284277

285-
private ServerBuilder<?> serverBuilder(int port, File serverCertChainFile,
286-
File serverPrivateKeyFile, X509Certificate[] serverTrustedCaCerts) throws IOException {
278+
private ServerBuilder<?> serverBuilder(int port, InputStream serverCertChain,
279+
InputStream serverPrivateKey, X509Certificate[] serverTrustedCaCerts) throws IOException {
287280
SslContextBuilder sslContextBuilder
288-
= SslContextBuilder.forServer(serverCertChainFile, serverPrivateKeyFile);
281+
= SslContextBuilder.forServer(serverCertChain, serverPrivateKey);
289282
GrpcSslContexts.configure(sslContextBuilder, sslProvider);
290283
sslContextBuilder.trustManager(serverTrustedCaCerts)
291284
.clientAuth(ClientAuth.REQUIRE);

netty/src/main/java/io/grpc/netty/GrpcSslContexts.java

+33
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import com.google.errorprone.annotations.CanIgnoreReturnValue;
2222
import io.grpc.ExperimentalApi;
23+
import io.grpc.internal.GrpcUtil;
2324
import io.netty.handler.codec.http2.Http2SecurityUtil;
2425
import io.netty.handler.ssl.ApplicationProtocolConfig;
2526
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
@@ -30,6 +31,7 @@
3031
import io.netty.handler.ssl.SslProvider;
3132
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
3233
import java.io.File;
34+
import java.io.InputStream;
3335
import java.util.Arrays;
3436
import java.util.Collections;
3537
import java.util.List;
@@ -104,6 +106,21 @@ public static SslContextBuilder forServer(File keyCertChainFile, File keyFile) {
104106
return configure(SslContextBuilder.forServer(keyCertChainFile, keyFile));
105107
}
106108

109+
/**
110+
* Creates a SslContextBuilder with ciphers and APN appropriate for gRPC.
111+
*
112+
* @see SslContextBuilder#forServer(InputStream, InputStream)
113+
* @see #configure(SslContextBuilder)
114+
*/
115+
public static SslContextBuilder forServer(InputStream keyCertChain, InputStream key) {
116+
try {
117+
return configure(SslContextBuilder.forServer(keyCertChain, key));
118+
} finally {
119+
GrpcUtil.closeQuietly(keyCertChain);
120+
GrpcUtil.closeQuietly(key);
121+
}
122+
}
123+
107124
/**
108125
* Creates a SslContextBuilder with ciphers and APN appropriate for gRPC.
109126
*
@@ -115,6 +132,22 @@ public static SslContextBuilder forServer(
115132
return configure(SslContextBuilder.forServer(keyCertChainFile, keyFile, keyPassword));
116133
}
117134

135+
/**
136+
* Creates a SslContextBuilder with ciphers and APN appropriate for gRPC.
137+
*
138+
* @see SslContextBuilder#forServer(InputStream, InputStream, String)
139+
* @see #configure(SslContextBuilder)
140+
*/
141+
public static SslContextBuilder forServer(
142+
InputStream keyCertChain, InputStream key, String keyPassword) {
143+
try {
144+
return configure(SslContextBuilder.forServer(keyCertChain, key, keyPassword));
145+
} finally {
146+
GrpcUtil.closeQuietly(keyCertChain);
147+
GrpcUtil.closeQuietly(key);
148+
}
149+
}
150+
118151
/**
119152
* Set ciphers and APN appropriate for gRPC. Precisely what is set is permitted to change, so if
120153
* an application requires particular settings it should override the options set here.

0 commit comments

Comments
 (0)