Skip to content

Commit c28a7e3

Browse files
okhttp: Per-rpc call option authority verification (#11754)
1 parent 8f6a16f commit c28a7e3

File tree

10 files changed

+1141
-123
lines changed

10 files changed

+1141
-123
lines changed

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

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.grpc.internal;
1818

19+
import java.io.ByteArrayInputStream;
1920
import java.io.IOException;
2021
import java.io.InputStream;
2122
import java.security.GeneralSecurityException;
@@ -36,8 +37,21 @@ public final class CertificateUtils {
3637
/**
3738
* Creates X509TrustManagers using the provided CA certs.
3839
*/
39-
public static TrustManager[] createTrustManager(InputStream rootCerts)
40+
public static TrustManager[] createTrustManager(byte[] rootCerts)
4041
throws GeneralSecurityException {
42+
InputStream rootCertsStream = new ByteArrayInputStream(rootCerts);
43+
try {
44+
return CertificateUtils.createTrustManager(rootCertsStream);
45+
} finally {
46+
GrpcUtil.closeQuietly(rootCertsStream);
47+
}
48+
}
49+
50+
/**
51+
* Creates X509TrustManagers using the provided input stream of CA certs.
52+
*/
53+
public static TrustManager[] createTrustManager(InputStream rootCerts)
54+
throws GeneralSecurityException {
4155
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
4256
try {
4357
ks.load(null, null);
@@ -52,13 +66,13 @@ public static TrustManager[] createTrustManager(InputStream rootCerts)
5266
}
5367

5468
TrustManagerFactory trustManagerFactory =
55-
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
69+
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
5670
trustManagerFactory.init(ks);
5771
return trustManagerFactory.getTrustManagers();
5872
}
5973

6074
private static X509Certificate[] getX509Certificates(InputStream inputStream)
61-
throws CertificateException {
75+
throws CertificateException {
6276
CertificateFactory factory = CertificateFactory.getInstance("X.509");
6377
Collection<? extends Certificate> certs = factory.generateCertificates(inputStream);
6478
return certs.toArray(new X509Certificate[0]);
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright 2024 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc.okhttp;
18+
19+
import java.io.IOException;
20+
import javax.net.ssl.HandshakeCompletedListener;
21+
import javax.net.ssl.SSLSession;
22+
import javax.net.ssl.SSLSocket;
23+
24+
/** A no-op ssl socket, to facilitate overriding only the required methods in specific
25+
* implementations.
26+
*/
27+
class NoopSslSocket extends SSLSocket {
28+
@Override
29+
public String[] getSupportedCipherSuites() {
30+
return new String[0];
31+
}
32+
33+
@Override
34+
public String[] getEnabledCipherSuites() {
35+
return new String[0];
36+
}
37+
38+
@Override
39+
public void setEnabledCipherSuites(String[] suites) {
40+
41+
}
42+
43+
@Override
44+
public String[] getSupportedProtocols() {
45+
return new String[0];
46+
}
47+
48+
@Override
49+
public String[] getEnabledProtocols() {
50+
return new String[0];
51+
}
52+
53+
@Override
54+
public void setEnabledProtocols(String[] protocols) {
55+
56+
}
57+
58+
@Override
59+
public SSLSession getSession() {
60+
return null;
61+
}
62+
63+
@Override
64+
public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
65+
66+
}
67+
68+
@Override
69+
public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
70+
71+
}
72+
73+
@Override
74+
public void startHandshake() throws IOException {
75+
76+
}
77+
78+
@Override
79+
public void setUseClientMode(boolean mode) {
80+
81+
}
82+
83+
@Override
84+
public boolean getUseClientMode() {
85+
return false;
86+
}
87+
88+
@Override
89+
public void setNeedClientAuth(boolean need) {
90+
91+
}
92+
93+
@Override
94+
public boolean getNeedClientAuth() {
95+
return false;
96+
}
97+
98+
@Override
99+
public void setWantClientAuth(boolean want) {
100+
101+
}
102+
103+
@Override
104+
public boolean getWantClientAuth() {
105+
return false;
106+
}
107+
108+
@Override
109+
public void setEnableSessionCreation(boolean flag) {
110+
111+
}
112+
113+
@Override
114+
public boolean getEnableSessionCreation() {
115+
return false;
116+
}
117+
}

okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.grpc.okhttp;
1818

1919
import static com.google.common.base.Preconditions.checkNotNull;
20+
import static io.grpc.internal.CertificateUtils.createTrustManager;
2021
import static io.grpc.internal.GrpcUtil.DEFAULT_KEEPALIVE_TIMEOUT_NANOS;
2122
import static io.grpc.internal.GrpcUtil.KEEPALIVE_TIME_NANOS_DISABLED;
2223

@@ -89,6 +90,7 @@ public final class OkHttpChannelBuilder extends ForwardingChannelBuilder2<OkHttp
8990
public static final int DEFAULT_FLOW_CONTROL_WINDOW = 65535;
9091

9192
private final ManagedChannelImplBuilder managedChannelImplBuilder;
93+
private final ChannelCredentials channelCredentials;
9294
private TransportTracer.Factory transportTracerFactory = TransportTracer.getDefaultFactory();
9395

9496

@@ -206,6 +208,7 @@ private OkHttpChannelBuilder(String target) {
206208
new OkHttpChannelTransportFactoryBuilder(),
207209
new OkHttpChannelDefaultPortProvider());
208210
this.freezeSecurityConfiguration = false;
211+
this.channelCredentials = null;
209212
}
210213

211214
OkHttpChannelBuilder(
@@ -218,6 +221,7 @@ private OkHttpChannelBuilder(String target) {
218221
this.sslSocketFactory = factory;
219222
this.negotiationType = factory == null ? NegotiationType.PLAINTEXT : NegotiationType.TLS;
220223
this.freezeSecurityConfiguration = true;
224+
this.channelCredentials = channelCreds;
221225
}
222226

223227
private final class OkHttpChannelTransportFactoryBuilder
@@ -534,7 +538,8 @@ OkHttpTransportFactory buildTransportFactory() {
534538
keepAliveWithoutCalls,
535539
maxInboundMetadataSize,
536540
transportTracerFactory,
537-
useGetForSafeMethods);
541+
useGetForSafeMethods,
542+
channelCredentials);
538543
}
539544

540545
OkHttpChannelBuilder disableCheckAuthority() {
@@ -777,6 +782,7 @@ static final class OkHttpTransportFactory implements ClientTransportFactory {
777782
private final boolean keepAliveWithoutCalls;
778783
final int maxInboundMetadataSize;
779784
final boolean useGetForSafeMethods;
785+
private final ChannelCredentials channelCredentials;
780786
private boolean closed;
781787

782788
private OkHttpTransportFactory(
@@ -794,7 +800,8 @@ private OkHttpTransportFactory(
794800
boolean keepAliveWithoutCalls,
795801
int maxInboundMetadataSize,
796802
TransportTracer.Factory transportTracerFactory,
797-
boolean useGetForSafeMethods) {
803+
boolean useGetForSafeMethods,
804+
ChannelCredentials channelCredentials) {
798805
this.executorPool = executorPool;
799806
this.executor = executorPool.getObject();
800807
this.scheduledExecutorServicePool = scheduledExecutorServicePool;
@@ -812,6 +819,7 @@ private OkHttpTransportFactory(
812819
this.keepAliveWithoutCalls = keepAliveWithoutCalls;
813820
this.maxInboundMetadataSize = maxInboundMetadataSize;
814821
this.useGetForSafeMethods = useGetForSafeMethods;
822+
this.channelCredentials = channelCredentials;
815823

816824
this.transportTracerFactory =
817825
Preconditions.checkNotNull(transportTracerFactory, "transportTracerFactory");
@@ -839,7 +847,8 @@ public void run() {
839847
options.getUserAgent(),
840848
options.getEagAttributes(),
841849
options.getHttpConnectProxiedSocketAddress(),
842-
tooManyPingsRunnable);
850+
tooManyPingsRunnable,
851+
channelCredentials);
843852
if (enableKeepAlive) {
844853
transport.enableKeepAlive(
845854
true, keepAliveTimeNanosState.get(), keepAliveTimeoutNanos, keepAliveWithoutCalls);
@@ -875,7 +884,8 @@ public SwapChannelCredentialsResult swapChannelCredentials(ChannelCredentials ch
875884
keepAliveWithoutCalls,
876885
maxInboundMetadataSize,
877886
transportTracerFactory,
878-
useGetForSafeMethods);
887+
useGetForSafeMethods,
888+
channelCredentials);
879889
return new SwapChannelCredentialsResult(factory, result.callCredentials);
880890
}
881891

okhttp/src/main/java/io/grpc/okhttp/OkHttpClientStream.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ private void streamReady(Metadata metadata, String path) {
409409
transport.isUsingPlaintext());
410410
// TODO(b/145386688): This access should be guarded by 'this.transport.lock'; instead found:
411411
// 'this.lock'
412-
transport.streamReadyToStart(OkHttpClientStream.this);
412+
transport.streamReadyToStart(OkHttpClientStream.this, authority);
413413
}
414414

415415
Tag tag() {

0 commit comments

Comments
 (0)