1 /* 2 * Copyright 2020 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.certprovider; 18 19 import io.envoyproxy.envoy.config.core.v3.Node; 20 import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateValidationContext; 21 import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext; 22 import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext.CertificateProviderInstance; 23 import io.grpc.xds.Bootstrapper.CertificateProviderInfo; 24 import io.grpc.xds.EnvoyServerProtoData.BaseTlsContext; 25 import io.grpc.xds.internal.security.CommonTlsContextUtil; 26 import io.grpc.xds.internal.security.DynamicSslContextProvider; 27 import java.security.PrivateKey; 28 import java.security.cert.X509Certificate; 29 import java.util.List; 30 import java.util.Map; 31 import javax.annotation.Nullable; 32 33 /** Base class for {@link CertProviderClientSslContextProvider}. */ 34 abstract class CertProviderSslContextProvider extends DynamicSslContextProvider implements 35 CertificateProvider.Watcher { 36 37 @Nullable private final CertificateProviderStore.Handle certHandle; 38 @Nullable private final CertificateProviderStore.Handle rootCertHandle; 39 @Nullable private final CertificateProviderInstance certInstance; 40 @Nullable private final CertificateProviderInstance rootCertInstance; 41 @Nullable protected PrivateKey savedKey; 42 @Nullable protected List<X509Certificate> savedCertChain; 43 @Nullable protected List<X509Certificate> savedTrustedRoots; 44 CertProviderSslContextProvider( Node node, @Nullable Map<String, CertificateProviderInfo> certProviders, CertificateProviderInstance certInstance, CertificateProviderInstance rootCertInstance, CertificateValidationContext staticCertValidationContext, BaseTlsContext tlsContext, CertificateProviderStore certificateProviderStore)45 protected CertProviderSslContextProvider( 46 Node node, 47 @Nullable Map<String, CertificateProviderInfo> certProviders, 48 CertificateProviderInstance certInstance, 49 CertificateProviderInstance rootCertInstance, 50 CertificateValidationContext staticCertValidationContext, 51 BaseTlsContext tlsContext, 52 CertificateProviderStore certificateProviderStore) { 53 super(tlsContext, staticCertValidationContext); 54 this.certInstance = certInstance; 55 this.rootCertInstance = rootCertInstance; 56 String certInstanceName = null; 57 if (certInstance != null && certInstance.isInitialized()) { 58 certInstanceName = certInstance.getInstanceName(); 59 CertificateProviderInfo certProviderInstanceConfig = 60 getCertProviderConfig(certProviders, certInstanceName); 61 certHandle = certProviderInstanceConfig == null ? null 62 : certificateProviderStore.createOrGetProvider( 63 certInstance.getCertificateName(), 64 certProviderInstanceConfig.pluginName(), 65 certProviderInstanceConfig.config(), 66 this, 67 true); 68 } else { 69 certHandle = null; 70 } 71 if (rootCertInstance != null 72 && rootCertInstance.isInitialized() 73 && !rootCertInstance.getInstanceName().equals(certInstanceName)) { 74 CertificateProviderInfo certProviderInstanceConfig = 75 getCertProviderConfig(certProviders, rootCertInstance.getInstanceName()); 76 rootCertHandle = certProviderInstanceConfig == null ? null 77 : certificateProviderStore.createOrGetProvider( 78 rootCertInstance.getCertificateName(), 79 certProviderInstanceConfig.pluginName(), 80 certProviderInstanceConfig.config(), 81 this, 82 true); 83 } else { 84 rootCertHandle = null; 85 } 86 } 87 getCertProviderConfig( @ullable Map<String, CertificateProviderInfo> certProviders, String pluginInstanceName)88 private static CertificateProviderInfo getCertProviderConfig( 89 @Nullable Map<String, CertificateProviderInfo> certProviders, String pluginInstanceName) { 90 return certProviders != null ? certProviders.get(pluginInstanceName) : null; 91 } 92 93 @Nullable getCertProviderInstance( CommonTlsContext commonTlsContext)94 protected static CertificateProviderInstance getCertProviderInstance( 95 CommonTlsContext commonTlsContext) { 96 if (commonTlsContext.hasTlsCertificateProviderInstance()) { 97 return CommonTlsContextUtil.convert(commonTlsContext.getTlsCertificateProviderInstance()); 98 } else if (commonTlsContext.hasTlsCertificateCertificateProviderInstance()) { 99 return commonTlsContext.getTlsCertificateCertificateProviderInstance(); 100 } 101 return null; 102 } 103 104 @Nullable getStaticValidationContext( CommonTlsContext commonTlsContext)105 protected static CertificateValidationContext getStaticValidationContext( 106 CommonTlsContext commonTlsContext) { 107 if (commonTlsContext.hasValidationContext()) { 108 return commonTlsContext.getValidationContext(); 109 } else if (commonTlsContext.hasCombinedValidationContext()) { 110 CommonTlsContext.CombinedCertificateValidationContext combinedValidationContext = 111 commonTlsContext.getCombinedValidationContext(); 112 if (combinedValidationContext.hasDefaultValidationContext()) { 113 return combinedValidationContext.getDefaultValidationContext(); 114 } 115 } 116 return null; 117 } 118 119 @Nullable getRootCertProviderInstance( CommonTlsContext commonTlsContext)120 protected static CommonTlsContext.CertificateProviderInstance getRootCertProviderInstance( 121 CommonTlsContext commonTlsContext) { 122 CertificateValidationContext certValidationContext = getStaticValidationContext( 123 commonTlsContext); 124 if (certValidationContext != null && certValidationContext.hasCaCertificateProviderInstance()) { 125 return CommonTlsContextUtil.convert(certValidationContext.getCaCertificateProviderInstance()); 126 } 127 if (commonTlsContext.hasCombinedValidationContext()) { 128 CommonTlsContext.CombinedCertificateValidationContext combinedValidationContext = 129 commonTlsContext.getCombinedValidationContext(); 130 if (combinedValidationContext.hasValidationContextCertificateProviderInstance()) { 131 return combinedValidationContext.getValidationContextCertificateProviderInstance(); 132 } 133 } else if (commonTlsContext.hasValidationContextCertificateProviderInstance()) { 134 return commonTlsContext.getValidationContextCertificateProviderInstance(); 135 } 136 return null; 137 } 138 139 @Override updateCertificate(PrivateKey key, List<X509Certificate> certChain)140 public final void updateCertificate(PrivateKey key, List<X509Certificate> certChain) { 141 savedKey = key; 142 savedCertChain = certChain; 143 updateSslContextWhenReady(); 144 } 145 146 @Override updateTrustedRoots(List<X509Certificate> trustedRoots)147 public final void updateTrustedRoots(List<X509Certificate> trustedRoots) { 148 savedTrustedRoots = trustedRoots; 149 updateSslContextWhenReady(); 150 } 151 updateSslContextWhenReady()152 private void updateSslContextWhenReady() { 153 if (isMtls()) { 154 if (savedKey != null && savedTrustedRoots != null) { 155 updateSslContext(); 156 clearKeysAndCerts(); 157 } 158 } else if (isClientSideTls()) { 159 if (savedTrustedRoots != null) { 160 updateSslContext(); 161 clearKeysAndCerts(); 162 } 163 } else if (isServerSideTls()) { 164 if (savedKey != null) { 165 updateSslContext(); 166 clearKeysAndCerts(); 167 } 168 } 169 } 170 clearKeysAndCerts()171 private void clearKeysAndCerts() { 172 savedKey = null; 173 savedTrustedRoots = null; 174 savedCertChain = null; 175 } 176 isMtls()177 protected final boolean isMtls() { 178 return certInstance != null && rootCertInstance != null; 179 } 180 isClientSideTls()181 protected final boolean isClientSideTls() { 182 return rootCertInstance != null && certInstance == null; 183 } 184 isServerSideTls()185 protected final boolean isServerSideTls() { 186 return certInstance != null && rootCertInstance == null; 187 } 188 189 @Override generateCertificateValidationContext()190 protected final CertificateValidationContext generateCertificateValidationContext() { 191 return staticCertificateValidationContext; 192 } 193 194 @Override close()195 public final void close() { 196 if (certHandle != null) { 197 certHandle.close(); 198 } 199 if (rootCertHandle != null) { 200 rootCertHandle.close(); 201 } 202 } 203 } 204