1 /* 2 * Copyright 2014 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 static com.google.common.base.Preconditions.checkNotNull; 20 import static io.grpc.internal.GrpcUtil.DEFAULT_KEEPALIVE_TIMEOUT_NANOS; 21 import static io.grpc.internal.GrpcUtil.KEEPALIVE_TIME_NANOS_DISABLED; 22 23 import com.google.common.annotations.VisibleForTesting; 24 import com.google.common.base.Preconditions; 25 import io.grpc.CallCredentials; 26 import io.grpc.ChannelCredentials; 27 import io.grpc.ChannelLogger; 28 import io.grpc.ChoiceChannelCredentials; 29 import io.grpc.CompositeCallCredentials; 30 import io.grpc.CompositeChannelCredentials; 31 import io.grpc.ExperimentalApi; 32 import io.grpc.InsecureChannelCredentials; 33 import io.grpc.Internal; 34 import io.grpc.ManagedChannelBuilder; 35 import io.grpc.TlsChannelCredentials; 36 import io.grpc.internal.AbstractManagedChannelImplBuilder; 37 import io.grpc.internal.AtomicBackoff; 38 import io.grpc.internal.ClientTransportFactory; 39 import io.grpc.internal.ConnectionClientTransport; 40 import io.grpc.internal.FixedObjectPool; 41 import io.grpc.internal.GrpcUtil; 42 import io.grpc.internal.KeepAliveManager; 43 import io.grpc.internal.ManagedChannelImplBuilder; 44 import io.grpc.internal.ManagedChannelImplBuilder.ChannelBuilderDefaultPortProvider; 45 import io.grpc.internal.ManagedChannelImplBuilder.ClientTransportFactoryBuilder; 46 import io.grpc.internal.ObjectPool; 47 import io.grpc.internal.SharedResourceHolder.Resource; 48 import io.grpc.internal.SharedResourcePool; 49 import io.grpc.internal.TransportTracer; 50 import io.grpc.okhttp.internal.CipherSuite; 51 import io.grpc.okhttp.internal.ConnectionSpec; 52 import io.grpc.okhttp.internal.Platform; 53 import io.grpc.okhttp.internal.TlsVersion; 54 import io.grpc.util.CertificateUtils; 55 import java.io.ByteArrayInputStream; 56 import java.io.IOException; 57 import java.net.InetSocketAddress; 58 import java.net.SocketAddress; 59 import java.security.GeneralSecurityException; 60 import java.security.KeyStore; 61 import java.security.PrivateKey; 62 import java.security.cert.X509Certificate; 63 import java.util.EnumSet; 64 import java.util.Set; 65 import java.util.concurrent.Executor; 66 import java.util.concurrent.ExecutorService; 67 import java.util.concurrent.Executors; 68 import java.util.concurrent.ScheduledExecutorService; 69 import java.util.concurrent.TimeUnit; 70 import java.util.logging.Level; 71 import java.util.logging.Logger; 72 import javax.annotation.CheckReturnValue; 73 import javax.annotation.Nullable; 74 import javax.net.SocketFactory; 75 import javax.net.ssl.HostnameVerifier; 76 import javax.net.ssl.KeyManager; 77 import javax.net.ssl.KeyManagerFactory; 78 import javax.net.ssl.SSLContext; 79 import javax.net.ssl.SSLSocketFactory; 80 import javax.net.ssl.TrustManager; 81 import javax.net.ssl.TrustManagerFactory; 82 import javax.security.auth.x500.X500Principal; 83 84 /** Convenience class for building channels with the OkHttp transport. */ 85 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1785") 86 public final class OkHttpChannelBuilder extends 87 AbstractManagedChannelImplBuilder<OkHttpChannelBuilder> { 88 private static final Logger log = Logger.getLogger(OkHttpChannelBuilder.class.getName()); 89 public static final int DEFAULT_FLOW_CONTROL_WINDOW = 65535; 90 91 private final ManagedChannelImplBuilder managedChannelImplBuilder; 92 private TransportTracer.Factory transportTracerFactory = TransportTracer.getDefaultFactory(); 93 94 95 /** Identifies the negotiation used for starting up HTTP/2. */ 96 private enum NegotiationType { 97 /** Uses TLS ALPN/NPN negotiation, assumes an SSL connection. */ 98 TLS, 99 100 /** 101 * Just assume the connection is plaintext (non-SSL) and the remote endpoint supports HTTP/2 102 * directly without an upgrade. 103 */ 104 PLAINTEXT 105 } 106 107 // @VisibleForTesting 108 static final ConnectionSpec INTERNAL_DEFAULT_CONNECTION_SPEC = 109 new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 110 .cipherSuites( 111 // The following items should be sync with Netty's Http2SecurityUtil.CIPHERS. 112 CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 113 CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 114 CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 115 CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 116 CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 117 CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 118 119 // TLS 1.3 does not work so far. See issues: 120 // https://github.com/grpc/grpc-java/issues/7765 121 // 122 // TLS 1.3 123 //CipherSuite.TLS_AES_128_GCM_SHA256, 124 //CipherSuite.TLS_AES_256_GCM_SHA384, 125 //CipherSuite.TLS_CHACHA20_POLY1305_SHA256 126 ) 127 .tlsVersions(/*TlsVersion.TLS_1_3,*/ TlsVersion.TLS_1_2) 128 .supportsTlsExtensions(true) 129 .build(); 130 131 private static final long AS_LARGE_AS_INFINITE = TimeUnit.DAYS.toNanos(1000L); 132 private static final Resource<Executor> SHARED_EXECUTOR = 133 new Resource<Executor>() { 134 @Override 135 public Executor create() { 136 return Executors.newCachedThreadPool(GrpcUtil.getThreadFactory("grpc-okhttp-%d", true)); 137 } 138 139 @Override 140 public void close(Executor executor) { 141 ((ExecutorService) executor).shutdown(); 142 } 143 }; 144 static final ObjectPool<Executor> DEFAULT_TRANSPORT_EXECUTOR_POOL = 145 SharedResourcePool.forResource(SHARED_EXECUTOR); 146 147 /** Creates a new builder for the given server host and port. */ forAddress(String host, int port)148 public static OkHttpChannelBuilder forAddress(String host, int port) { 149 return new OkHttpChannelBuilder(host, port); 150 } 151 152 /** Creates a new builder with the given host and port. */ forAddress(String host, int port, ChannelCredentials creds)153 public static OkHttpChannelBuilder forAddress(String host, int port, ChannelCredentials creds) { 154 return forTarget(GrpcUtil.authorityFromHostAndPort(host, port), creds); 155 } 156 157 /** 158 * Creates a new builder for the given target that will be resolved by 159 * {@link io.grpc.NameResolver}. 160 */ forTarget(String target)161 public static OkHttpChannelBuilder forTarget(String target) { 162 return new OkHttpChannelBuilder(target); 163 } 164 165 /** 166 * Creates a new builder for the given target that will be resolved by 167 * {@link io.grpc.NameResolver}. 168 */ forTarget(String target, ChannelCredentials creds)169 public static OkHttpChannelBuilder forTarget(String target, ChannelCredentials creds) { 170 SslSocketFactoryResult result = sslSocketFactoryFrom(creds); 171 if (result.error != null) { 172 throw new IllegalArgumentException(result.error); 173 } 174 return new OkHttpChannelBuilder(target, creds, result.callCredentials, result.factory); 175 } 176 177 private ObjectPool<Executor> transportExecutorPool = DEFAULT_TRANSPORT_EXECUTOR_POOL; 178 private ObjectPool<ScheduledExecutorService> scheduledExecutorServicePool = 179 SharedResourcePool.forResource(GrpcUtil.TIMER_SERVICE); 180 181 private SocketFactory socketFactory; 182 private SSLSocketFactory sslSocketFactory; 183 private final boolean freezeSecurityConfiguration; 184 private HostnameVerifier hostnameVerifier; 185 private ConnectionSpec connectionSpec = INTERNAL_DEFAULT_CONNECTION_SPEC; 186 private NegotiationType negotiationType = NegotiationType.TLS; 187 private long keepAliveTimeNanos = KEEPALIVE_TIME_NANOS_DISABLED; 188 private long keepAliveTimeoutNanos = DEFAULT_KEEPALIVE_TIMEOUT_NANOS; 189 private int flowControlWindow = DEFAULT_FLOW_CONTROL_WINDOW; 190 private boolean keepAliveWithoutCalls; 191 private int maxInboundMetadataSize = Integer.MAX_VALUE; 192 193 /** 194 * If true, indicates that the transport may use the GET method for RPCs, and may include the 195 * request body in the query params. 196 */ 197 private final boolean useGetForSafeMethods = false; 198 OkHttpChannelBuilder(String host, int port)199 private OkHttpChannelBuilder(String host, int port) { 200 this(GrpcUtil.authorityFromHostAndPort(host, port)); 201 } 202 OkHttpChannelBuilder(String target)203 private OkHttpChannelBuilder(String target) { 204 managedChannelImplBuilder = new ManagedChannelImplBuilder(target, 205 new OkHttpChannelTransportFactoryBuilder(), 206 new OkHttpChannelDefaultPortProvider()); 207 this.freezeSecurityConfiguration = false; 208 } 209 OkHttpChannelBuilder( String target, ChannelCredentials channelCreds, CallCredentials callCreds, SSLSocketFactory factory)210 OkHttpChannelBuilder( 211 String target, ChannelCredentials channelCreds, CallCredentials callCreds, 212 SSLSocketFactory factory) { 213 managedChannelImplBuilder = new ManagedChannelImplBuilder( 214 target, channelCreds, callCreds, 215 new OkHttpChannelTransportFactoryBuilder(), 216 new OkHttpChannelDefaultPortProvider()); 217 this.sslSocketFactory = factory; 218 this.negotiationType = factory == null ? NegotiationType.PLAINTEXT : NegotiationType.TLS; 219 this.freezeSecurityConfiguration = true; 220 } 221 222 private final class OkHttpChannelTransportFactoryBuilder 223 implements ClientTransportFactoryBuilder { 224 @Override buildClientTransportFactory()225 public ClientTransportFactory buildClientTransportFactory() { 226 return buildTransportFactory(); 227 } 228 } 229 230 private final class OkHttpChannelDefaultPortProvider 231 implements ChannelBuilderDefaultPortProvider { 232 @Override getDefaultPort()233 public int getDefaultPort() { 234 return OkHttpChannelBuilder.this.getDefaultPort(); 235 } 236 } 237 238 @Internal 239 @Override delegate()240 protected ManagedChannelBuilder<?> delegate() { 241 return managedChannelImplBuilder; 242 } 243 244 @VisibleForTesting setTransportTracerFactory(TransportTracer.Factory transportTracerFactory)245 OkHttpChannelBuilder setTransportTracerFactory(TransportTracer.Factory transportTracerFactory) { 246 this.transportTracerFactory = transportTracerFactory; 247 return this; 248 } 249 250 /** 251 * Override the default executor necessary for internal transport use. 252 * 253 * <p>The channel does not take ownership of the given executor. It is the caller' responsibility 254 * to shutdown the executor when appropriate. 255 */ transportExecutor(@ullable Executor transportExecutor)256 public OkHttpChannelBuilder transportExecutor(@Nullable Executor transportExecutor) { 257 if (transportExecutor == null) { 258 this.transportExecutorPool = DEFAULT_TRANSPORT_EXECUTOR_POOL; 259 } else { 260 this.transportExecutorPool = new FixedObjectPool<>(transportExecutor); 261 } 262 return this; 263 } 264 265 /** 266 * Override the default {@link SocketFactory} used to create sockets. If the socket factory is not 267 * set or set to null, a default one will be used. 268 * 269 * @since 1.20.0 270 */ socketFactory(@ullable SocketFactory socketFactory)271 public OkHttpChannelBuilder socketFactory(@Nullable SocketFactory socketFactory) { 272 this.socketFactory = socketFactory; 273 return this; 274 } 275 276 /** 277 * Sets the negotiation type for the HTTP/2 connection. 278 * 279 * <p>If TLS is enabled a default {@link SSLSocketFactory} is created using the best 280 * {@link java.security.Provider} available and is NOT based on 281 * {@link SSLSocketFactory#getDefault}. To more precisely control the TLS configuration call 282 * {@link #sslSocketFactory} to override the socket factory used. 283 * 284 * <p>Default: <code>TLS</code> 285 * 286 * @deprecated use {@link #usePlaintext()} or {@link #useTransportSecurity()} instead. 287 */ 288 @Deprecated negotiationType(io.grpc.okhttp.NegotiationType type)289 public OkHttpChannelBuilder negotiationType(io.grpc.okhttp.NegotiationType type) { 290 Preconditions.checkState(!freezeSecurityConfiguration, 291 "Cannot change security when using ChannelCredentials"); 292 Preconditions.checkNotNull(type, "type"); 293 switch (type) { 294 case TLS: 295 negotiationType = NegotiationType.TLS; 296 break; 297 case PLAINTEXT: 298 negotiationType = NegotiationType.PLAINTEXT; 299 break; 300 default: 301 throw new AssertionError("Unknown negotiation type: " + type); 302 } 303 return this; 304 } 305 306 /** 307 * {@inheritDoc} 308 * 309 * @since 1.3.0 310 */ 311 @Override keepAliveTime(long keepAliveTime, TimeUnit timeUnit)312 public OkHttpChannelBuilder keepAliveTime(long keepAliveTime, TimeUnit timeUnit) { 313 Preconditions.checkArgument(keepAliveTime > 0L, "keepalive time must be positive"); 314 keepAliveTimeNanos = timeUnit.toNanos(keepAliveTime); 315 keepAliveTimeNanos = KeepAliveManager.clampKeepAliveTimeInNanos(keepAliveTimeNanos); 316 if (keepAliveTimeNanos >= AS_LARGE_AS_INFINITE) { 317 // Bump keepalive time to infinite. This disables keepalive. 318 keepAliveTimeNanos = KEEPALIVE_TIME_NANOS_DISABLED; 319 } 320 return this; 321 } 322 323 /** 324 * {@inheritDoc} 325 * 326 * @since 1.3.0 327 */ 328 @Override keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit)329 public OkHttpChannelBuilder keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit) { 330 Preconditions.checkArgument(keepAliveTimeout > 0L, "keepalive timeout must be positive"); 331 keepAliveTimeoutNanos = timeUnit.toNanos(keepAliveTimeout); 332 keepAliveTimeoutNanos = KeepAliveManager.clampKeepAliveTimeoutInNanos(keepAliveTimeoutNanos); 333 return this; 334 } 335 336 /** 337 * Sets the flow control window in bytes. If not called, the default value 338 * is {@link #DEFAULT_FLOW_CONTROL_WINDOW}). 339 */ flowControlWindow(int flowControlWindow)340 public OkHttpChannelBuilder flowControlWindow(int flowControlWindow) { 341 Preconditions.checkState(flowControlWindow > 0, "flowControlWindow must be positive"); 342 this.flowControlWindow = flowControlWindow; 343 return this; 344 } 345 346 /** 347 * {@inheritDoc} 348 * 349 * @since 1.3.0 350 * @see #keepAliveTime(long, TimeUnit) 351 */ 352 @Override keepAliveWithoutCalls(boolean enable)353 public OkHttpChannelBuilder keepAliveWithoutCalls(boolean enable) { 354 keepAliveWithoutCalls = enable; 355 return this; 356 } 357 358 /** 359 * Override the default {@link SSLSocketFactory} and enable TLS negotiation. 360 */ sslSocketFactory(SSLSocketFactory factory)361 public OkHttpChannelBuilder sslSocketFactory(SSLSocketFactory factory) { 362 Preconditions.checkState(!freezeSecurityConfiguration, 363 "Cannot change security when using ChannelCredentials"); 364 this.sslSocketFactory = factory; 365 negotiationType = NegotiationType.TLS; 366 return this; 367 } 368 369 /** 370 * Set the hostname verifier to use when using TLS negotiation. The hostnameVerifier is only used 371 * if using TLS negotiation. If the hostname verifier is not set, a default hostname verifier is 372 * used. 373 * 374 * <p>Be careful when setting a custom hostname verifier! By setting a non-null value, you are 375 * replacing all default verification behavior. If the hostname verifier you supply does not 376 * effectively supply the same checks, you may be removing the security assurances that TLS aims 377 * to provide.</p> 378 * 379 * <p>This method should not be used to avoid hostname verification, even during testing, since 380 * {@link #overrideAuthority} is a safer alternative as it does not disable any security checks. 381 * </p> 382 * 383 * @see io.grpc.okhttp.internal.OkHostnameVerifier 384 * 385 * @since 1.6.0 386 * @return this 387 * 388 */ hostnameVerifier(@ullable HostnameVerifier hostnameVerifier)389 public OkHttpChannelBuilder hostnameVerifier(@Nullable HostnameVerifier hostnameVerifier) { 390 Preconditions.checkState(!freezeSecurityConfiguration, 391 "Cannot change security when using ChannelCredentials"); 392 this.hostnameVerifier = hostnameVerifier; 393 return this; 394 } 395 396 /** 397 * For secure connection, provides a ConnectionSpec to specify Cipher suite and 398 * TLS versions. 399 * 400 * <p>By default a modern, HTTP/2-compatible spec will be used. 401 * 402 * <p>This method is only used when building a secure connection. For plaintext 403 * connection, use {@link #usePlaintext()} instead. 404 * 405 * @throws IllegalArgumentException 406 * If {@code connectionSpec} is not with TLS 407 */ connectionSpec( com.squareup.okhttp.ConnectionSpec connectionSpec)408 public OkHttpChannelBuilder connectionSpec( 409 com.squareup.okhttp.ConnectionSpec connectionSpec) { 410 Preconditions.checkState(!freezeSecurityConfiguration, 411 "Cannot change security when using ChannelCredentials"); 412 Preconditions.checkArgument(connectionSpec.isTls(), "plaintext ConnectionSpec is not accepted"); 413 this.connectionSpec = Utils.convertSpec(connectionSpec); 414 return this; 415 } 416 417 /** 418 * Sets the connection specification used for secure connections. 419 * 420 * <p>By default a modern, HTTP/2-compatible spec will be used. 421 * 422 * <p>This method is only used when building a secure connection. For plaintext 423 * connection, use {@link #usePlaintext()} instead. 424 * 425 * @param tlsVersions List of tls versions. 426 * @param cipherSuites List of cipher suites. 427 * 428 * @since 1.43.0 429 */ tlsConnectionSpec( String[] tlsVersions, String[] cipherSuites)430 public OkHttpChannelBuilder tlsConnectionSpec( 431 String[] tlsVersions, String[] cipherSuites) { 432 Preconditions.checkState(!freezeSecurityConfiguration, 433 "Cannot change security when using ChannelCredentials"); 434 Preconditions.checkNotNull(tlsVersions, "tls versions must not null"); 435 Preconditions.checkNotNull(cipherSuites, "ciphers must not null"); 436 437 this.connectionSpec = new ConnectionSpec.Builder(true) 438 .supportsTlsExtensions(true) 439 .tlsVersions(tlsVersions) 440 .cipherSuites(cipherSuites) 441 .build(); 442 return this; 443 } 444 445 /** Sets the negotiation type for the HTTP/2 connection to plaintext. */ 446 @Override usePlaintext()447 public OkHttpChannelBuilder usePlaintext() { 448 Preconditions.checkState(!freezeSecurityConfiguration, 449 "Cannot change security when using ChannelCredentials"); 450 negotiationType = NegotiationType.PLAINTEXT; 451 return this; 452 } 453 454 /** 455 * Sets the negotiation type for the HTTP/2 connection to TLS (this is the default). 456 * 457 * <p>With TLS enabled, a default {@link SSLSocketFactory} is created using the best {@link 458 * java.security.Provider} available and is NOT based on {@link SSLSocketFactory#getDefault}. To 459 * more precisely control the TLS configuration call {@link #sslSocketFactory(SSLSocketFactory)} 460 * to override the socket factory used. 461 */ 462 @Override useTransportSecurity()463 public OkHttpChannelBuilder useTransportSecurity() { 464 Preconditions.checkState(!freezeSecurityConfiguration, 465 "Cannot change security when using ChannelCredentials"); 466 negotiationType = NegotiationType.TLS; 467 return this; 468 } 469 470 /** 471 * Provides a custom scheduled executor service. 472 * 473 * <p>It's an optional parameter. If the user has not provided a scheduled executor service when 474 * the channel is built, the builder will use a static cached thread pool. 475 * 476 * @return this 477 * 478 * @since 1.11.0 479 */ scheduledExecutorService( ScheduledExecutorService scheduledExecutorService)480 public OkHttpChannelBuilder scheduledExecutorService( 481 ScheduledExecutorService scheduledExecutorService) { 482 this.scheduledExecutorServicePool = 483 new FixedObjectPool<>(checkNotNull(scheduledExecutorService, "scheduledExecutorService")); 484 return this; 485 } 486 487 /** 488 * Sets the maximum size of metadata allowed to be received. {@code Integer.MAX_VALUE} disables 489 * the enforcement. Defaults to no limit ({@code Integer.MAX_VALUE}). 490 * 491 * <p>The implementation does not currently limit memory usage; this value is checked only after 492 * the metadata is decoded from the wire. It does prevent large metadata from being passed to the 493 * application. 494 * 495 * @param bytes the maximum size of received metadata 496 * @return this 497 * @throws IllegalArgumentException if bytes is non-positive 498 * @since 1.17.0 499 */ 500 @Override maxInboundMetadataSize(int bytes)501 public OkHttpChannelBuilder maxInboundMetadataSize(int bytes) { 502 Preconditions.checkArgument(bytes > 0, "maxInboundMetadataSize must be > 0"); 503 this.maxInboundMetadataSize = bytes; 504 return this; 505 } 506 507 /** 508 * Sets the maximum message size allowed for a single gRPC frame. If an inbound messages 509 * larger than this limit is received it will not be processed and the RPC will fail with 510 * RESOURCE_EXHAUSTED. 511 */ 512 @Override maxInboundMessageSize(int max)513 public OkHttpChannelBuilder maxInboundMessageSize(int max) { 514 Preconditions.checkArgument(max >= 0, "negative max"); 515 maxInboundMessageSize = max; 516 return this; 517 } 518 buildTransportFactory()519 OkHttpTransportFactory buildTransportFactory() { 520 boolean enableKeepAlive = keepAliveTimeNanos != KEEPALIVE_TIME_NANOS_DISABLED; 521 return new OkHttpTransportFactory( 522 transportExecutorPool, 523 scheduledExecutorServicePool, 524 socketFactory, 525 createSslSocketFactory(), 526 hostnameVerifier, 527 connectionSpec, 528 maxInboundMessageSize, 529 enableKeepAlive, 530 keepAliveTimeNanos, 531 keepAliveTimeoutNanos, 532 flowControlWindow, 533 keepAliveWithoutCalls, 534 maxInboundMetadataSize, 535 transportTracerFactory, 536 useGetForSafeMethods); 537 } 538 disableCheckAuthority()539 OkHttpChannelBuilder disableCheckAuthority() { 540 this.managedChannelImplBuilder.disableCheckAuthority(); 541 return this; 542 } 543 enableCheckAuthority()544 OkHttpChannelBuilder enableCheckAuthority() { 545 this.managedChannelImplBuilder.enableCheckAuthority(); 546 return this; 547 } 548 getDefaultPort()549 int getDefaultPort() { 550 switch (negotiationType) { 551 case PLAINTEXT: 552 return GrpcUtil.DEFAULT_PORT_PLAINTEXT; 553 case TLS: 554 return GrpcUtil.DEFAULT_PORT_SSL; 555 default: 556 throw new AssertionError(negotiationType + " not handled"); 557 } 558 } 559 setStatsEnabled(boolean value)560 void setStatsEnabled(boolean value) { 561 this.managedChannelImplBuilder.setStatsEnabled(value); 562 } 563 564 @VisibleForTesting 565 @Nullable createSslSocketFactory()566 SSLSocketFactory createSslSocketFactory() { 567 switch (negotiationType) { 568 case TLS: 569 try { 570 if (sslSocketFactory == null) { 571 SSLContext sslContext = SSLContext.getInstance("Default", Platform.get().getProvider()); 572 sslSocketFactory = sslContext.getSocketFactory(); 573 } 574 return sslSocketFactory; 575 } catch (GeneralSecurityException gse) { 576 throw new RuntimeException("TLS Provider failure", gse); 577 } 578 case PLAINTEXT: 579 return null; 580 default: 581 throw new RuntimeException("Unknown negotiation type: " + negotiationType); 582 } 583 } 584 585 private static final EnumSet<TlsChannelCredentials.Feature> understoodTlsFeatures = 586 EnumSet.of( 587 TlsChannelCredentials.Feature.MTLS, TlsChannelCredentials.Feature.CUSTOM_MANAGERS); 588 sslSocketFactoryFrom(ChannelCredentials creds)589 static SslSocketFactoryResult sslSocketFactoryFrom(ChannelCredentials creds) { 590 if (creds instanceof TlsChannelCredentials) { 591 TlsChannelCredentials tlsCreds = (TlsChannelCredentials) creds; 592 Set<TlsChannelCredentials.Feature> incomprehensible = 593 tlsCreds.incomprehensible(understoodTlsFeatures); 594 if (!incomprehensible.isEmpty()) { 595 return SslSocketFactoryResult.error( 596 "TLS features not understood: " + incomprehensible); 597 } 598 KeyManager[] km = null; 599 if (tlsCreds.getKeyManagers() != null) { 600 km = tlsCreds.getKeyManagers().toArray(new KeyManager[0]); 601 } else if (tlsCreds.getPrivateKey() != null) { 602 if (tlsCreds.getPrivateKeyPassword() != null) { 603 return SslSocketFactoryResult.error("byte[]-based private key with password unsupported. " 604 + "Use unencrypted file or KeyManager"); 605 } 606 try { 607 km = createKeyManager(tlsCreds.getCertificateChain(), tlsCreds.getPrivateKey()); 608 } catch (GeneralSecurityException gse) { 609 log.log(Level.FINE, "Exception loading private key from credential", gse); 610 return SslSocketFactoryResult.error("Unable to load private key: " + gse.getMessage()); 611 } 612 } // else don't have a client cert 613 TrustManager[] tm = null; 614 if (tlsCreds.getTrustManagers() != null) { 615 tm = tlsCreds.getTrustManagers().toArray(new TrustManager[0]); 616 } else if (tlsCreds.getRootCertificates() != null) { 617 try { 618 tm = createTrustManager(tlsCreds.getRootCertificates()); 619 } catch (GeneralSecurityException gse) { 620 log.log(Level.FINE, "Exception loading root certificates from credential", gse); 621 return SslSocketFactoryResult.error( 622 "Unable to load root certificates: " + gse.getMessage()); 623 } 624 } // else use system default 625 SSLContext sslContext; 626 try { 627 sslContext = SSLContext.getInstance("TLS", Platform.get().getProvider()); 628 sslContext.init(km, tm, null); 629 } catch (GeneralSecurityException gse) { 630 throw new RuntimeException("TLS Provider failure", gse); 631 } 632 return SslSocketFactoryResult.factory(sslContext.getSocketFactory()); 633 634 } else if (creds instanceof InsecureChannelCredentials) { 635 return SslSocketFactoryResult.plaintext(); 636 637 } else if (creds instanceof CompositeChannelCredentials) { 638 CompositeChannelCredentials compCreds = (CompositeChannelCredentials) creds; 639 return sslSocketFactoryFrom(compCreds.getChannelCredentials()) 640 .withCallCredentials(compCreds.getCallCredentials()); 641 642 } else if (creds instanceof SslSocketFactoryChannelCredentials.ChannelCredentials) { 643 SslSocketFactoryChannelCredentials.ChannelCredentials factoryCreds = 644 (SslSocketFactoryChannelCredentials.ChannelCredentials) creds; 645 return SslSocketFactoryResult.factory(factoryCreds.getFactory()); 646 647 } else if (creds instanceof ChoiceChannelCredentials) { 648 ChoiceChannelCredentials choiceCreds = (ChoiceChannelCredentials) creds; 649 StringBuilder error = new StringBuilder(); 650 for (ChannelCredentials innerCreds : choiceCreds.getCredentialsList()) { 651 SslSocketFactoryResult result = sslSocketFactoryFrom(innerCreds); 652 if (result.error == null) { 653 return result; 654 } 655 error.append(", "); 656 error.append(result.error); 657 } 658 return SslSocketFactoryResult.error(error.substring(2)); 659 660 } else { 661 return SslSocketFactoryResult.error( 662 "Unsupported credential type: " + creds.getClass().getName()); 663 } 664 } 665 createKeyManager(byte[] certChain, byte[] privateKey)666 static KeyManager[] createKeyManager(byte[] certChain, byte[] privateKey) 667 throws GeneralSecurityException { 668 X509Certificate[] chain; 669 ByteArrayInputStream inCertChain = new ByteArrayInputStream(certChain); 670 try { 671 chain = CertificateUtils.getX509Certificates(inCertChain); 672 } finally { 673 GrpcUtil.closeQuietly(inCertChain); 674 } 675 PrivateKey key; 676 ByteArrayInputStream inPrivateKey = new ByteArrayInputStream(privateKey); 677 try { 678 key = CertificateUtils.getPrivateKey(inPrivateKey); 679 } catch (IOException uee) { 680 throw new GeneralSecurityException("Unable to decode private key", uee); 681 } finally { 682 GrpcUtil.closeQuietly(inPrivateKey); 683 } 684 KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); 685 try { 686 ks.load(null, null); 687 } catch (IOException ex) { 688 // Shouldn't really happen, as we're not loading any data. 689 throw new GeneralSecurityException(ex); 690 } 691 ks.setKeyEntry("key", key, new char[0], chain); 692 693 KeyManagerFactory keyManagerFactory = 694 KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 695 keyManagerFactory.init(ks, new char[0]); 696 return keyManagerFactory.getKeyManagers(); 697 } 698 createTrustManager(byte[] rootCerts)699 static TrustManager[] createTrustManager(byte[] rootCerts) throws GeneralSecurityException { 700 KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); 701 try { 702 ks.load(null, null); 703 } catch (IOException ex) { 704 // Shouldn't really happen, as we're not loading any data. 705 throw new GeneralSecurityException(ex); 706 } 707 X509Certificate[] certs; 708 ByteArrayInputStream in = new ByteArrayInputStream(rootCerts); 709 try { 710 certs = CertificateUtils.getX509Certificates(in); 711 } finally { 712 GrpcUtil.closeQuietly(in); 713 } 714 for (X509Certificate cert : certs) { 715 X500Principal principal = cert.getSubjectX500Principal(); 716 ks.setCertificateEntry(principal.getName("RFC2253"), cert); 717 } 718 719 TrustManagerFactory trustManagerFactory = 720 TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 721 trustManagerFactory.init(ks); 722 return trustManagerFactory.getTrustManagers(); 723 } 724 725 static final class SslSocketFactoryResult { 726 /** {@code null} implies plaintext if {@code error == null}. */ 727 public final SSLSocketFactory factory; 728 public final CallCredentials callCredentials; 729 public final String error; 730 SslSocketFactoryResult(SSLSocketFactory factory, CallCredentials creds, String error)731 private SslSocketFactoryResult(SSLSocketFactory factory, CallCredentials creds, String error) { 732 this.factory = factory; 733 this.callCredentials = creds; 734 this.error = error; 735 } 736 error(String error)737 public static SslSocketFactoryResult error(String error) { 738 return new SslSocketFactoryResult( 739 null, null, Preconditions.checkNotNull(error, "error")); 740 } 741 plaintext()742 public static SslSocketFactoryResult plaintext() { 743 return new SslSocketFactoryResult(null, null, null); 744 } 745 factory( SSLSocketFactory factory)746 public static SslSocketFactoryResult factory( 747 SSLSocketFactory factory) { 748 return new SslSocketFactoryResult( 749 Preconditions.checkNotNull(factory, "factory"), null, null); 750 } 751 withCallCredentials(CallCredentials callCreds)752 public SslSocketFactoryResult withCallCredentials(CallCredentials callCreds) { 753 Preconditions.checkNotNull(callCreds, "callCreds"); 754 if (error != null) { 755 return this; 756 } 757 if (this.callCredentials != null) { 758 callCreds = new CompositeCallCredentials(this.callCredentials, callCreds); 759 } 760 return new SslSocketFactoryResult(factory, callCreds, null); 761 } 762 } 763 764 765 /** 766 * Creates OkHttp transports. Exposed for internal use, as it should be private. 767 */ 768 @Internal 769 static final class OkHttpTransportFactory implements ClientTransportFactory { 770 private final ObjectPool<Executor> executorPool; 771 final Executor executor; 772 private final ObjectPool<ScheduledExecutorService> scheduledExecutorServicePool; 773 final ScheduledExecutorService scheduledExecutorService; 774 final TransportTracer.Factory transportTracerFactory; 775 final SocketFactory socketFactory; 776 @Nullable final SSLSocketFactory sslSocketFactory; 777 @Nullable 778 final HostnameVerifier hostnameVerifier; 779 final ConnectionSpec connectionSpec; 780 final int maxMessageSize; 781 private final boolean enableKeepAlive; 782 private final long keepAliveTimeNanos; 783 private final AtomicBackoff keepAliveBackoff; 784 private final long keepAliveTimeoutNanos; 785 final int flowControlWindow; 786 private final boolean keepAliveWithoutCalls; 787 final int maxInboundMetadataSize; 788 final boolean useGetForSafeMethods; 789 private boolean closed; 790 OkHttpTransportFactory( ObjectPool<Executor> executorPool, ObjectPool<ScheduledExecutorService> scheduledExecutorServicePool, @Nullable SocketFactory socketFactory, @Nullable SSLSocketFactory sslSocketFactory, @Nullable HostnameVerifier hostnameVerifier, ConnectionSpec connectionSpec, int maxMessageSize, boolean enableKeepAlive, long keepAliveTimeNanos, long keepAliveTimeoutNanos, int flowControlWindow, boolean keepAliveWithoutCalls, int maxInboundMetadataSize, TransportTracer.Factory transportTracerFactory, boolean useGetForSafeMethods)791 private OkHttpTransportFactory( 792 ObjectPool<Executor> executorPool, 793 ObjectPool<ScheduledExecutorService> scheduledExecutorServicePool, 794 @Nullable SocketFactory socketFactory, 795 @Nullable SSLSocketFactory sslSocketFactory, 796 @Nullable HostnameVerifier hostnameVerifier, 797 ConnectionSpec connectionSpec, 798 int maxMessageSize, 799 boolean enableKeepAlive, 800 long keepAliveTimeNanos, 801 long keepAliveTimeoutNanos, 802 int flowControlWindow, 803 boolean keepAliveWithoutCalls, 804 int maxInboundMetadataSize, 805 TransportTracer.Factory transportTracerFactory, 806 boolean useGetForSafeMethods) { 807 this.executorPool = executorPool; 808 this.executor = executorPool.getObject(); 809 this.scheduledExecutorServicePool = scheduledExecutorServicePool; 810 this.scheduledExecutorService = scheduledExecutorServicePool.getObject(); 811 this.socketFactory = socketFactory; 812 this.sslSocketFactory = sslSocketFactory; 813 this.hostnameVerifier = hostnameVerifier; 814 this.connectionSpec = connectionSpec; 815 this.maxMessageSize = maxMessageSize; 816 this.enableKeepAlive = enableKeepAlive; 817 this.keepAliveTimeNanos = keepAliveTimeNanos; 818 this.keepAliveBackoff = new AtomicBackoff("keepalive time nanos", keepAliveTimeNanos); 819 this.keepAliveTimeoutNanos = keepAliveTimeoutNanos; 820 this.flowControlWindow = flowControlWindow; 821 this.keepAliveWithoutCalls = keepAliveWithoutCalls; 822 this.maxInboundMetadataSize = maxInboundMetadataSize; 823 this.useGetForSafeMethods = useGetForSafeMethods; 824 825 this.transportTracerFactory = 826 Preconditions.checkNotNull(transportTracerFactory, "transportTracerFactory"); 827 } 828 829 @Override newClientTransport( SocketAddress addr, ClientTransportOptions options, ChannelLogger channelLogger)830 public ConnectionClientTransport newClientTransport( 831 SocketAddress addr, ClientTransportOptions options, ChannelLogger channelLogger) { 832 if (closed) { 833 throw new IllegalStateException("The transport factory is closed."); 834 } 835 final AtomicBackoff.State keepAliveTimeNanosState = keepAliveBackoff.getState(); 836 Runnable tooManyPingsRunnable = new Runnable() { 837 @Override 838 public void run() { 839 keepAliveTimeNanosState.backoff(); 840 } 841 }; 842 InetSocketAddress inetSocketAddr = (InetSocketAddress) addr; 843 // TODO(carl-mastrangelo): Pass channelLogger in. 844 OkHttpClientTransport transport = new OkHttpClientTransport( 845 this, 846 inetSocketAddr, 847 options.getAuthority(), 848 options.getUserAgent(), 849 options.getEagAttributes(), 850 options.getHttpConnectProxiedSocketAddress(), 851 tooManyPingsRunnable); 852 if (enableKeepAlive) { 853 transport.enableKeepAlive( 854 true, keepAliveTimeNanosState.get(), keepAliveTimeoutNanos, keepAliveWithoutCalls); 855 } 856 return transport; 857 } 858 859 @Override getScheduledExecutorService()860 public ScheduledExecutorService getScheduledExecutorService() { 861 return scheduledExecutorService; 862 } 863 864 @Nullable 865 @CheckReturnValue 866 @Override swapChannelCredentials(ChannelCredentials channelCreds)867 public SwapChannelCredentialsResult swapChannelCredentials(ChannelCredentials channelCreds) { 868 SslSocketFactoryResult result = sslSocketFactoryFrom(channelCreds); 869 if (result.error != null) { 870 return null; 871 } 872 ClientTransportFactory factory = new OkHttpTransportFactory( 873 executorPool, 874 scheduledExecutorServicePool, 875 socketFactory, 876 result.factory, 877 hostnameVerifier, 878 connectionSpec, 879 maxMessageSize, 880 enableKeepAlive, 881 keepAliveTimeNanos, 882 keepAliveTimeoutNanos, 883 flowControlWindow, 884 keepAliveWithoutCalls, 885 maxInboundMetadataSize, 886 transportTracerFactory, 887 useGetForSafeMethods); 888 return new SwapChannelCredentialsResult(factory, result.callCredentials); 889 } 890 891 @Override close()892 public void close() { 893 if (closed) { 894 return; 895 } 896 closed = true; 897 898 executorPool.returnObject(executor); 899 scheduledExecutorServicePool.returnObject(scheduledExecutorService); 900 } 901 } 902 } 903