1 /* 2 * Copyright 2019 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.xds.internal.security; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 import static com.google.common.base.Preconditions.checkState; 21 22 import com.google.common.annotations.VisibleForTesting; 23 import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext; 24 import io.grpc.Internal; 25 import io.grpc.xds.EnvoyServerProtoData.BaseTlsContext; 26 import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext; 27 import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext; 28 import io.grpc.xds.internal.security.trust.XdsTrustManagerFactory; 29 import io.netty.handler.ssl.ClientAuth; 30 import io.netty.handler.ssl.SslContext; 31 import io.netty.handler.ssl.SslContextBuilder; 32 import java.io.IOException; 33 import java.security.cert.CertStoreException; 34 import java.security.cert.CertificateException; 35 import java.util.concurrent.Executor; 36 37 /** 38 * A SslContextProvider is a "container" or provider of SslContext. This is used by gRPC-xds to 39 * obtain an SslContext, so is not part of the public API of gRPC. This "container" may represent a 40 * stream that is receiving the requested secret(s) or it could represent file-system based 41 * secret(s) that are dynamic. 42 */ 43 @Internal 44 public abstract class SslContextProvider implements Closeable { 45 46 protected final BaseTlsContext tlsContext; 47 48 @VisibleForTesting public abstract static class Callback { 49 private final Executor executor; 50 Callback(Executor executor)51 protected Callback(Executor executor) { 52 this.executor = executor; 53 } 54 getExecutor()55 @VisibleForTesting public Executor getExecutor() { 56 return executor; 57 } 58 59 /** Informs callee of new/updated SslContext. */ updateSslContext(SslContext sslContext)60 @VisibleForTesting public abstract void updateSslContext(SslContext sslContext); 61 62 /** Informs callee of an exception that was generated. */ onException(Throwable throwable)63 @VisibleForTesting protected abstract void onException(Throwable throwable); 64 } 65 SslContextProvider(BaseTlsContext tlsContext)66 protected SslContextProvider(BaseTlsContext tlsContext) { 67 this.tlsContext = checkNotNull(tlsContext, "tlsContext"); 68 } 69 getCommonTlsContext()70 protected CommonTlsContext getCommonTlsContext() { 71 return tlsContext.getCommonTlsContext(); 72 } 73 setClientAuthValues( SslContextBuilder sslContextBuilder, XdsTrustManagerFactory xdsTrustManagerFactory)74 protected void setClientAuthValues( 75 SslContextBuilder sslContextBuilder, XdsTrustManagerFactory xdsTrustManagerFactory) 76 throws CertificateException, IOException, CertStoreException { 77 DownstreamTlsContext downstreamTlsContext = getDownstreamTlsContext(); 78 if (xdsTrustManagerFactory != null) { 79 sslContextBuilder.trustManager(xdsTrustManagerFactory); 80 sslContextBuilder.clientAuth( 81 downstreamTlsContext.isRequireClientCertificate() 82 ? ClientAuth.REQUIRE 83 : ClientAuth.OPTIONAL); 84 } else { 85 sslContextBuilder.clientAuth(ClientAuth.NONE); 86 } 87 } 88 89 /** Returns the DownstreamTlsContext in this SslContextProvider if this is server side. **/ getDownstreamTlsContext()90 public DownstreamTlsContext getDownstreamTlsContext() { 91 checkState(tlsContext instanceof DownstreamTlsContext, 92 "expected DownstreamTlsContext"); 93 return ((DownstreamTlsContext)tlsContext); 94 } 95 96 /** Returns the UpstreamTlsContext in this SslContextProvider if this is client side. **/ getUpstreamTlsContext()97 public UpstreamTlsContext getUpstreamTlsContext() { 98 checkState(tlsContext instanceof UpstreamTlsContext, 99 "expected UpstreamTlsContext"); 100 return ((UpstreamTlsContext)tlsContext); 101 } 102 103 /** Closes this provider and releases any resources. */ 104 @Override close()105 public abstract void close(); 106 107 /** 108 * Registers a callback on the given executor. The callback will run when SslContext becomes 109 * available or immediately if the result is already available. 110 */ addCallback(Callback callback)111 public abstract void addCallback(Callback callback); 112 performCallback( final SslContextGetter sslContextGetter, final Callback callback)113 protected final void performCallback( 114 final SslContextGetter sslContextGetter, final Callback callback) { 115 checkNotNull(sslContextGetter, "sslContextGetter"); 116 checkNotNull(callback, "callback"); 117 callback.executor.execute( 118 new Runnable() { 119 @Override 120 public void run() { 121 try { 122 SslContext sslContext = sslContextGetter.get(); 123 callback.updateSslContext(sslContext); 124 } catch (Throwable e) { 125 callback.onException(e); 126 } 127 } 128 }); 129 } 130 131 /** Allows implementations to compute or get SslContext. */ 132 protected interface SslContextGetter { get()133 SslContext get() throws Exception; 134 } 135 } 136