Skip to content

Commit 916d0d5

Browse files
committed
Review comments and use reflection for X509ExtendedTrustManager.
1 parent 2594842 commit 916d0d5

File tree

3 files changed

+91
-45
lines changed

3 files changed

+91
-45
lines changed

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,16 @@
6363
import java.util.Map;
6464
import java.util.concurrent.Executor;
6565
import java.util.concurrent.TimeUnit;
66+
import java.util.logging.Logger;
6667
import javax.annotation.Nullable;
6768

6869
/**
6970
* A Netty-based {@link ConnectionClientTransport} implementation.
7071
*/
7172
class NettyClientTransport implements ConnectionClientTransport {
7273

74+
private static final boolean enablePerRpcAuthorityCheck =
75+
GrpcUtil.getFlag("GRPC_ENABLE_PER_RPC_AUTHORITY_CHECK", false);
7376
private final InternalLogId logId;
7477
private final Map<ChannelOption<?>, ?> channelOptions;
7578
private final SocketAddress remoteAddress;
@@ -105,6 +108,7 @@ class NettyClientTransport implements ConnectionClientTransport {
105108
private final ChannelLogger channelLogger;
106109
private final boolean useGetForSafeMethods;
107110
private final Ticker ticker;
111+
private final Logger logger = Logger.getLogger(NettyClientTransport.class.getName());
108112

109113
NettyClientTransport(
110114
SocketAddress address,
@@ -197,11 +201,11 @@ public ClientStream newStream(
197201
if (callOptions.getAuthority() != null) {
198202
Status verificationStatus = negotiator.verifyAuthority(callOptions.getAuthority());
199203
if (!verificationStatus.isOk()) {
200-
if (GrpcUtil.getFlag("GRPC_ENABLE_PER_RPC_AUTHORITY_CHECK", false)) {
204+
if (enablePerRpcAuthorityCheck) {
201205
return new FailingClientStream(verificationStatus, tracers);
202206
}
203-
channelLogger.log(ChannelLogger.ChannelLogLevel.WARNING, "Authority '{}' specified via "
204-
+ "call options for rpc did not match peer certificate's subject names.");
207+
logger.warning("Authority verification for the rpc failed (This will be an error in the "
208+
+ "future) with error status: " + verificationStatus.getDescription());
205209
}
206210
}
207211
StatsTraceContext statsTraceCtx =

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

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import io.grpc.internal.GrpcUtil;
4848
import io.grpc.internal.NoopSslSession;
4949
import io.grpc.internal.ObjectPool;
50+
import io.netty.channel.Channel;
5051
import io.netty.channel.ChannelDuplexHandler;
5152
import io.netty.channel.ChannelFutureListener;
5253
import io.netty.channel.ChannelHandler;
@@ -61,6 +62,7 @@
6162
import io.netty.handler.codec.http2.Http2ClientUpgradeCodec;
6263
import io.netty.handler.proxy.HttpProxyHandler;
6364
import io.netty.handler.proxy.ProxyConnectionEvent;
65+
import io.netty.handler.ssl.ClientAuth;
6466
import io.netty.handler.ssl.OpenSsl;
6567
import io.netty.handler.ssl.OpenSslEngine;
6668
import io.netty.handler.ssl.SslContext;
@@ -70,6 +72,8 @@
7072
import io.netty.handler.ssl.SslProvider;
7173
import io.netty.util.AsciiString;
7274
import java.io.ByteArrayInputStream;
75+
import java.lang.reflect.InvocationTargetException;
76+
import java.lang.reflect.Method;
7377
import java.net.SocketAddress;
7478
import java.net.URI;
7579
import java.nio.channels.ClosedChannelException;
@@ -97,7 +101,7 @@
97101
import javax.net.ssl.SSLSession;
98102
import javax.net.ssl.TrustManager;
99103
import javax.net.ssl.TrustManagerFactory;
100-
import javax.net.ssl.X509ExtendedTrustManager;
104+
import javax.net.ssl.X509TrustManager;
101105
import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement;
102106

103107
/**
@@ -111,7 +115,16 @@ final class ProtocolNegotiators {
111115
private static final EnumSet<TlsServerCredentials.Feature> understoodServerTlsFeatures =
112116
EnumSet.of(
113117
TlsServerCredentials.Feature.MTLS, TlsServerCredentials.Feature.CUSTOM_MANAGERS);
114-
118+
private static Class<?> x509ExtendedTrustManagerClass;
119+
private static final Logger logger = Logger.getLogger(ProtocolNegotiators.class.getName());
120+
static {
121+
try {
122+
x509ExtendedTrustManagerClass = Class.forName("javax.net.ssl.X509ExtendedTrustManager");
123+
} catch (ClassNotFoundException e) {
124+
logger.info("javax.net.ssl.X509ExtendedTrustManager is not available. Authority override via call options" +
125+
"via call options will not be allowed.");
126+
}
127+
}
115128

116129
private ProtocolNegotiators() {
117130
}
@@ -149,14 +162,16 @@ public static FromChannelCredentialsResult from(ChannelCredentials creds) {
149162
}
150163
builder.trustManager(new FixedTrustManagerFactory(trustManagers));
151164
TrustManager x509ExtendedTrustManager = null;
152-
for (TrustManager trustManager: trustManagers) {
153-
if (trustManager instanceof X509ExtendedTrustManager) {
154-
x509ExtendedTrustManager = trustManager;
155-
break;
165+
if (x509ExtendedTrustManagerClass != null) {
166+
for (TrustManager trustManager : trustManagers) {
167+
if (x509ExtendedTrustManagerClass.isInstance(trustManager)) {
168+
x509ExtendedTrustManager = trustManager;
169+
break;
170+
}
156171
}
157172
}
158173
return FromChannelCredentialsResult.negotiator(tlsClientFactory(builder.build(),
159-
(X509ExtendedTrustManager) x509ExtendedTrustManager));
174+
(X509TrustManager) x509ExtendedTrustManager));
160175
} catch (SSLException | GeneralSecurityException ex) {
161176
log.log(Level.FINE, "Exception building SslContext", ex);
162177
return FromChannelCredentialsResult.error(
@@ -222,15 +237,15 @@ public static FromServerCredentialsResult from(ServerCredentials creds) {
222237
} // else use system default
223238
switch (tlsCreds.getClientAuth()) {
224239
case OPTIONAL:
225-
builder.clientAuth(io.netty.handler.ssl.ClientAuth.OPTIONAL);
240+
builder.clientAuth(ClientAuth.OPTIONAL);
226241
break;
227242

228243
case REQUIRE:
229-
builder.clientAuth(io.netty.handler.ssl.ClientAuth.REQUIRE);
244+
builder.clientAuth(ClientAuth.REQUIRE);
230245
break;
231246

232247
case NONE:
233-
builder.clientAuth(io.netty.handler.ssl.ClientAuth.NONE);
248+
builder.clientAuth(ClientAuth.NONE);
234249
break;
235250

236251
default:
@@ -286,17 +301,17 @@ private FromChannelCredentialsResult(ProtocolNegotiator.ClientFactory negotiator
286301

287302
public static FromChannelCredentialsResult error(String error) {
288303
return new FromChannelCredentialsResult(
289-
null, null, Preconditions.checkNotNull(error, "error"));
304+
null, null, checkNotNull(error, "error"));
290305
}
291306

292307
public static FromChannelCredentialsResult negotiator(
293308
ProtocolNegotiator.ClientFactory factory) {
294309
return new FromChannelCredentialsResult(
295-
Preconditions.checkNotNull(factory, "factory"), null, null);
310+
checkNotNull(factory, "factory"), null, null);
296311
}
297312

298313
public FromChannelCredentialsResult withCallCredentials(CallCredentials callCreds) {
299-
Preconditions.checkNotNull(callCreds, "callCreds");
314+
checkNotNull(callCreds, "callCreds");
300315
if (error != null) {
301316
return this;
302317
}
@@ -317,11 +332,11 @@ private FromServerCredentialsResult(ProtocolNegotiator.ServerFactory negotiator,
317332
}
318333

319334
public static FromServerCredentialsResult error(String error) {
320-
return new FromServerCredentialsResult(null, Preconditions.checkNotNull(error, "error"));
335+
return new FromServerCredentialsResult(null, checkNotNull(error, "error"));
321336
}
322337

323338
public static FromServerCredentialsResult negotiator(ProtocolNegotiator.ServerFactory factory) {
324-
return new FromServerCredentialsResult(Preconditions.checkNotNull(factory, "factory"), null);
339+
return new FromServerCredentialsResult(checkNotNull(factory, "factory"), null);
325340
}
326341
}
327342

@@ -336,7 +351,7 @@ private static final class FixedProtocolNegotiatorServerFactory
336351

337352
public FixedProtocolNegotiatorServerFactory(ProtocolNegotiator protocolNegotiator) {
338353
this.protocolNegotiator =
339-
Preconditions.checkNotNull(protocolNegotiator, "protocolNegotiator");
354+
checkNotNull(protocolNegotiator, "protocolNegotiator");
340355
}
341356

342357
@Override
@@ -378,7 +393,7 @@ static final class TlsProtocolNegotiatorServerFactory
378393
private final SslContext sslContext;
379394

380395
public TlsProtocolNegotiatorServerFactory(SslContext sslContext) {
381-
this.sslContext = Preconditions.checkNotNull(sslContext, "sslContext");
396+
this.sslContext = checkNotNull(sslContext, "sslContext");
382397
}
383398

384399
@Override
@@ -393,7 +408,7 @@ public ProtocolNegotiator newNegotiator(ObjectPool<? extends Executor> offloadEx
393408
*/
394409
public static ProtocolNegotiator serverTls(final SslContext sslContext,
395410
final ObjectPool<? extends Executor> executorPool) {
396-
Preconditions.checkNotNull(sslContext, "sslContext");
411+
checkNotNull(sslContext, "sslContext");
397412
final Executor executor;
398413
if (executorPool != null) {
399414
// The handlers here can out-live the {@link ProtocolNegotiator}.
@@ -575,6 +590,20 @@ protected void userEventTriggered0(ChannelHandlerContext ctx, Object evt) throws
575590
}
576591

577592
static final class ClientTlsProtocolNegotiator implements ProtocolNegotiator {
593+
private static final Logger logger = Logger.getLogger(ClientTlsProtocolNegotiator.class.getName());
594+
private static Method checkServerTrustedMethod;
595+
static {
596+
try {
597+
Class<?> x509ExtendedTrustManagerClass = Class.forName("javax.net.ssl.X509ExtendedTrustManager");
598+
checkServerTrustedMethod = x509ExtendedTrustManagerClass.getMethod("checkServerTrusted",
599+
X509Certificate[].class, String.class, SSLEngine.class);
600+
} catch (ClassNotFoundException e) {
601+
} catch (NoSuchMethodException e) {
602+
// Should never happen.
603+
logger.warning("Method checkServerTrusted not found in javax.net.ssl.X509ExtendedTrustManager");
604+
}
605+
}
606+
578607
@GuardedBy("this")
579608
private final LinkedHashMap<String, Status> peerVerificationResults =
580609
new LinkedHashMap<String, Status>() {
@@ -587,7 +616,7 @@ protected boolean removeEldestEntry(Map.Entry<String, Status> eldest) {
587616

588617
public ClientTlsProtocolNegotiator(SslContext sslContext,
589618
ObjectPool<? extends Executor> executorPool, Optional<Runnable> handshakeCompleteRunnable,
590-
X509ExtendedTrustManager x509ExtendedTrustManager) {
619+
X509TrustManager x509ExtendedTrustManager) {
591620
this.sslContext = checkNotNull(sslContext, "sslContext");
592621
this.executorPool = executorPool;
593622
if (this.executorPool != null) {
@@ -600,7 +629,7 @@ public ClientTlsProtocolNegotiator(SslContext sslContext,
600629
private final SslContext sslContext;
601630
private final ObjectPool<? extends Executor> executorPool;
602631
private final Optional<Runnable> handshakeCompleteRunnable;
603-
private final X509ExtendedTrustManager x509ExtendedTrustManager;
632+
private final X509TrustManager x509ExtendedTrustManager;
604633
private Executor executor;
605634

606635
@Override
@@ -640,7 +669,7 @@ public synchronized Status verifyAuthority(@Nonnull String authority) {
640669
try {
641670
verifyAuthorityAllowedForPeerCert(authority);
642671
peerVerificationStatus = Status.OK;
643-
} catch (SSLPeerUnverifiedException | CertificateException e) {
672+
} catch (SSLPeerUnverifiedException | CertificateException | InvocationTargetException | IllegalAccessException e) {
644673
peerVerificationStatus = Status.UNAVAILABLE.withDescription(
645674
String.format("Peer hostname verification during rpc failed for authority '%s'",
646675
authority)).withCause(e);
@@ -655,7 +684,11 @@ public void setSslEngine(SSLEngine sslEngine) {
655684
}
656685

657686
private void verifyAuthorityAllowedForPeerCert(String authority)
658-
throws SSLPeerUnverifiedException, CertificateException {
687+
throws SSLPeerUnverifiedException, CertificateException, InvocationTargetException,
688+
IllegalAccessException {
689+
if (checkServerTrustedMethod == null) {
690+
throw new IllegalStateException("Method checkServerTrusted not found in javax.net.ssl.X509ExtendedTrustManager");
691+
}
659692
SSLEngine sslEngineWrapper = new SslEngineWrapper(sslEngine, authority);
660693
// The typecasting of Certificate to X509Certificate should work because this method will only
661694
// be called when using TLS and thus X509.
@@ -664,7 +697,7 @@ private void verifyAuthorityAllowedForPeerCert(String authority)
664697
for (int i = 0; i < peerCertificates.length; i++) {
665698
x509PeerCertificates[i] = (X509Certificate) peerCertificates[i];
666699
}
667-
x509ExtendedTrustManager.checkServerTrusted(x509PeerCertificates, "RSA", sslEngineWrapper);
700+
checkServerTrustedMethod.invoke(x509ExtendedTrustManager, x509PeerCertificates, "RSA", sslEngineWrapper);
668701
}
669702

670703
@VisibleForTesting
@@ -768,7 +801,7 @@ private void propagateTlsComplete(ChannelHandlerContext ctx, SSLSession session)
768801

769802
@VisibleForTesting
770803
static HostPort parseAuthority(String authority) {
771-
URI uri = GrpcUtil.authorityToUri(Preconditions.checkNotNull(authority, "authority"));
804+
URI uri = GrpcUtil.authorityToUri(checkNotNull(authority, "authority"));
772805
String host;
773806
int port;
774807
if (uri.getHost() != null) {
@@ -791,42 +824,42 @@ static HostPort parseAuthority(String authority) {
791824

792825
/**
793826
* Returns a {@link ProtocolNegotiator} that ensures the pipeline is set up so that TLS will
794-
* be negotiated, the {@code handler} is added and writes to the {@link io.netty.channel.Channel}
827+
* be negotiated, the {@code handler} is added and writes to the {@link Channel}
795828
* may happen immediately, even before the TLS Handshake is complete.
796829
* @param executorPool a dedicated {@link Executor} pool for time-consuming TLS tasks
797830
*/
798831
public static ProtocolNegotiator tls(SslContext sslContext,
799832
ObjectPool<? extends Executor> executorPool, Optional<Runnable> handshakeCompleteRunnable,
800-
X509ExtendedTrustManager x509ExtendedTrustManager) {
833+
X509TrustManager x509ExtendedTrustManager) {
801834
return new ClientTlsProtocolNegotiator(sslContext, executorPool, handshakeCompleteRunnable,
802835
x509ExtendedTrustManager);
803836
}
804837

805838
/**
806839
* Returns a {@link ProtocolNegotiator} that ensures the pipeline is set up so that TLS will
807-
* be negotiated, the {@code handler} is added and writes to the {@link io.netty.channel.Channel}
840+
* be negotiated, the {@code handler} is added and writes to the {@link Channel}
808841
* may happen immediately, even before the TLS Handshake is complete.
809842
*/
810843
public static ProtocolNegotiator tls(SslContext sslContext,
811-
X509ExtendedTrustManager x509ExtendedTrustManager) {
844+
X509TrustManager x509ExtendedTrustManager) {
812845
return tls(sslContext, null, Optional.absent(),
813846
x509ExtendedTrustManager);
814847
}
815848

816849
public static ProtocolNegotiator.ClientFactory tlsClientFactory(SslContext sslContext,
817-
X509ExtendedTrustManager x509ExtendedTrustManager) {
850+
X509TrustManager x509ExtendedTrustManager) {
818851
return new TlsProtocolNegotiatorClientFactory(sslContext, x509ExtendedTrustManager);
819852
}
820853

821854
@VisibleForTesting
822855
static final class TlsProtocolNegotiatorClientFactory
823856
implements ProtocolNegotiator.ClientFactory {
824857
private final SslContext sslContext;
825-
private final X509ExtendedTrustManager x509ExtendedTrustManager;
858+
private final X509TrustManager x509ExtendedTrustManager;
826859

827860
public TlsProtocolNegotiatorClientFactory(SslContext sslContext,
828-
X509ExtendedTrustManager x509ExtendedTrustManager) {
829-
this.sslContext = Preconditions.checkNotNull(sslContext, "sslContext");
861+
X509TrustManager x509ExtendedTrustManager) {
862+
this.sslContext = checkNotNull(sslContext, "sslContext");
830863
this.x509ExtendedTrustManager = x509ExtendedTrustManager;
831864
}
832865

@@ -951,7 +984,7 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc
951984

952985
/**
953986
* Returns a {@link ChannelHandler} that ensures that the {@code handler} is added to the
954-
* pipeline writes to the {@link io.netty.channel.Channel} may happen immediately, even before it
987+
* pipeline writes to the {@link Channel} may happen immediately, even before it
955988
* is active.
956989
*/
957990
public static ProtocolNegotiator plaintext() {

0 commit comments

Comments
 (0)