4747import io .grpc .internal .ClientStream ;
4848import io .grpc .internal .ClientStreamListener .RpcProgress ;
4949import io .grpc .internal .ConnectionClientTransport ;
50+ import io .grpc .internal .FailingClientStream ;
5051import io .grpc .internal .GrpcAttributes ;
5152import io .grpc .internal .GrpcUtil ;
5253import io .grpc .internal .Http2Ping ;
7172import io .grpc .okhttp .internal .framed .Variant ;
7273import io .grpc .okhttp .internal .proxy .HttpUrl ;
7374import io .grpc .okhttp .internal .proxy .Request ;
75+ import io .grpc .util .CertificateUtils ;
7476import io .perfmark .PerfMark ;
77+ import java .io .ByteArrayInputStream ;
7578import java .io .EOFException ;
7679import java .io .IOException ;
80+ import java .io .InputStream ;
7781import java .net .InetSocketAddress ;
7882import java .net .Socket ;
7983import java .net .URI ;
84+ import java .security .GeneralSecurityException ;
85+ import java .security .KeyStore ;
86+ import java .security .cert .X509Certificate ;
87+ import java .util .Arrays ;
8088import java .util .Collections ;
8189import java .util .Deque ;
8290import java .util .EnumMap ;
104112import javax .net .ssl .SSLSession ;
105113import javax .net .ssl .SSLSocket ;
106114import javax .net .ssl .SSLSocketFactory ;
115+ import javax .net .ssl .TrustManager ;
116+ import javax .net .ssl .TrustManagerFactory ;
107117import javax .net .ssl .X509ExtendedTrustManager ;
118+ import javax .security .auth .x500 .X500Principal ;
108119import okio .Buffer ;
109120import okio .BufferedSink ;
110121import okio .BufferedSource ;
@@ -212,7 +223,7 @@ private static Map<ErrorCode, Status> buildErrorCodeToStatusMap() {
212223 private final boolean useGetForSafeMethods ;
213224 @ GuardedBy ("lock" )
214225 private final TransportTracer transportTracer ;
215- private Optional <X509ExtendedTrustManager > x509ExtendedTrustManager ;
226+ private Optional <TrustManager > x509ExtendedTrustManager ;
216227
217228 @ GuardedBy ("lock" )
218229 private final InUseStateAggregator <OkHttpClientStream > inUseState =
@@ -412,7 +423,19 @@ public ClientStream newStream(
412423 StatsTraceContext .newClientContext (tracers , getAttributes (), headers );
413424 if (callOptions .getAuthority () != null && channelCredentials instanceof TlsChannelCredentials ) {
414425 if (x509ExtendedTrustManager == null ) {
415-
426+ try {
427+ x509ExtendedTrustManager = getX509ExtendedTrustManager (
428+ (TlsChannelCredentials ) channelCredentials );
429+ } catch (GeneralSecurityException e ) {
430+ log .log (Level .FINE , "Failure getting X509ExtendedTrustManager from TlsCredentials" , e );
431+ return new FailingClientStream (Status .INTERNAL .withDescription (
432+ "Failure getting X509ExtendedTrustManager from TlsCredentials" ),
433+ tracers );
434+ }
435+ } else if (!x509ExtendedTrustManager .isPresent ()) {
436+ return new FailingClientStream (Status .INTERNAL .withDescription (
437+ "Can't allow authority override in rpc when X509ExtendedTrustManager is not available" ),
438+ tracers );
416439 }
417440 }
418441 // FIXME: it is likely wrong to pass the transportTracer here as it'll exit the lock's scope
@@ -435,6 +458,47 @@ public ClientStream newStream(
435458 }
436459 }
437460
461+ private Optional <TrustManager > getX509ExtendedTrustManager (TlsChannelCredentials tlsCreds )
462+ throws GeneralSecurityException {
463+ Optional <TrustManager > x509ExtendedTrustManager ;
464+ if (tlsCreds .getTrustManagers () != null ) {
465+ x509ExtendedTrustManager = tlsCreds .getTrustManagers ().stream ().filter (
466+ trustManager -> trustManager instanceof X509ExtendedTrustManager ).findFirst ();
467+ } else if (tlsCreds .getRootCertificates () != null ) {
468+ x509ExtendedTrustManager = getX509ExtendedTrustManager (new ByteArrayInputStream (
469+ tlsCreds .getRootCertificates ()));
470+ } else { // else use system default
471+ TrustManagerFactory tmf = TrustManagerFactory .getInstance (
472+ TrustManagerFactory .getDefaultAlgorithm ());
473+ tmf .init ((KeyStore ) null );
474+ x509ExtendedTrustManager = Arrays .stream (tmf .getTrustManagers ())
475+ .filter (trustManager -> trustManager instanceof X509ExtendedTrustManager ).findFirst ();
476+ }
477+ return x509ExtendedTrustManager ;
478+ }
479+
480+ private static Optional <TrustManager > getX509ExtendedTrustManager (InputStream rootCerts )
481+ throws GeneralSecurityException {
482+ KeyStore ks = KeyStore .getInstance (KeyStore .getDefaultType ());
483+ try {
484+ ks .load (null , null );
485+ } catch (IOException ex ) {
486+ // Shouldn't really happen, as we're not loading any data.
487+ throw new GeneralSecurityException (ex );
488+ }
489+ X509Certificate [] certs = CertificateUtils .getX509Certificates (rootCerts );
490+ for (X509Certificate cert : certs ) {
491+ X500Principal principal = cert .getSubjectX500Principal ();
492+ ks .setCertificateEntry (principal .getName ("RFC2253" ), cert );
493+ }
494+
495+ TrustManagerFactory trustManagerFactory =
496+ TrustManagerFactory .getInstance (TrustManagerFactory .getDefaultAlgorithm ());
497+ trustManagerFactory .init (ks );
498+ return Arrays .stream (trustManagerFactory .getTrustManagers ())
499+ .filter (trustManager -> trustManager instanceof X509ExtendedTrustManager ).findFirst ();
500+ }
501+
438502 @ GuardedBy ("lock" )
439503 void streamReadyToStart (OkHttpClientStream clientStream ) {
440504 if (goAwayStatus != null ) {
0 commit comments