blob: 1ec5876419618941db6c3fb206dead7d69421c20 [file] [log] [blame]
/*
* Copyright 2020 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc.xds.internal.certprovider;
import io.envoyproxy.envoy.config.core.v3.Node;
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateValidationContext;
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext;
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext.CertificateProviderInstance;
import io.grpc.xds.Bootstrapper.CertificateProviderInfo;
import io.grpc.xds.EnvoyServerProtoData.BaseTlsContext;
import io.grpc.xds.internal.sds.CommonTlsContextUtil;
import io.grpc.xds.internal.sds.DynamicSslContextProvider;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
/** Base class for {@link CertProviderClientSslContextProvider}. */
abstract class CertProviderSslContextProvider extends DynamicSslContextProvider implements
CertificateProvider.Watcher {
@Nullable private final CertificateProviderStore.Handle certHandle;
@Nullable private final CertificateProviderStore.Handle rootCertHandle;
@Nullable private final CertificateProviderInstance certInstance;
@Nullable private final CertificateProviderInstance rootCertInstance;
@Nullable protected PrivateKey savedKey;
@Nullable protected List<X509Certificate> savedCertChain;
@Nullable protected List<X509Certificate> savedTrustedRoots;
protected CertProviderSslContextProvider(
Node node,
@Nullable Map<String, CertificateProviderInfo> certProviders,
CertificateProviderInstance certInstance,
CertificateProviderInstance rootCertInstance,
CertificateValidationContext staticCertValidationContext,
BaseTlsContext tlsContext,
CertificateProviderStore certificateProviderStore) {
super(tlsContext, staticCertValidationContext);
this.certInstance = certInstance;
this.rootCertInstance = rootCertInstance;
String certInstanceName = null;
if (certInstance != null && certInstance.isInitialized()) {
certInstanceName = certInstance.getInstanceName();
CertificateProviderInfo certProviderInstanceConfig =
getCertProviderConfig(certProviders, certInstanceName);
certHandle = certProviderInstanceConfig == null ? null
: certificateProviderStore.createOrGetProvider(
certInstance.getCertificateName(),
certProviderInstanceConfig.getPluginName(),
certProviderInstanceConfig.getConfig(),
this,
true);
} else {
certHandle = null;
}
if (rootCertInstance != null
&& rootCertInstance.isInitialized()
&& !rootCertInstance.getInstanceName().equals(certInstanceName)) {
CertificateProviderInfo certProviderInstanceConfig =
getCertProviderConfig(certProviders, rootCertInstance.getInstanceName());
rootCertHandle = certProviderInstanceConfig == null ? null
: certificateProviderStore.createOrGetProvider(
rootCertInstance.getCertificateName(),
certProviderInstanceConfig.getPluginName(),
certProviderInstanceConfig.getConfig(),
this,
true);
} else {
rootCertHandle = null;
}
}
private static CertificateProviderInfo getCertProviderConfig(
@Nullable Map<String, CertificateProviderInfo> certProviders, String pluginInstanceName) {
return certProviders != null ? certProviders.get(pluginInstanceName) : null;
}
@Nullable
protected static CertificateProviderInstance getCertProviderInstance(
CommonTlsContext commonTlsContext) {
if (commonTlsContext.hasTlsCertificateProviderInstance()) {
return CommonTlsContextUtil.convert(commonTlsContext.getTlsCertificateProviderInstance());
} else if (commonTlsContext.hasTlsCertificateCertificateProviderInstance()) {
return commonTlsContext.getTlsCertificateCertificateProviderInstance();
}
return null;
}
@Nullable
protected static CertificateValidationContext getStaticValidationContext(
CommonTlsContext commonTlsContext) {
if (commonTlsContext.hasValidationContext()) {
return commonTlsContext.getValidationContext();
} else if (commonTlsContext.hasCombinedValidationContext()) {
CommonTlsContext.CombinedCertificateValidationContext combinedValidationContext =
commonTlsContext.getCombinedValidationContext();
if (combinedValidationContext.hasDefaultValidationContext()) {
return combinedValidationContext.getDefaultValidationContext();
}
}
return null;
}
@Nullable
protected static CommonTlsContext.CertificateProviderInstance getRootCertProviderInstance(
CommonTlsContext commonTlsContext) {
CertificateValidationContext certValidationContext = getStaticValidationContext(
commonTlsContext);
if (certValidationContext != null && certValidationContext.hasCaCertificateProviderInstance()) {
return CommonTlsContextUtil.convert(certValidationContext.getCaCertificateProviderInstance());
}
if (commonTlsContext.hasCombinedValidationContext()) {
CommonTlsContext.CombinedCertificateValidationContext combinedValidationContext =
commonTlsContext.getCombinedValidationContext();
if (combinedValidationContext.hasValidationContextCertificateProviderInstance()) {
return combinedValidationContext.getValidationContextCertificateProviderInstance();
}
} else if (commonTlsContext.hasValidationContextCertificateProviderInstance()) {
return commonTlsContext.getValidationContextCertificateProviderInstance();
}
return null;
}
@Override
public final void updateCertificate(PrivateKey key, List<X509Certificate> certChain) {
savedKey = key;
savedCertChain = certChain;
updateSslContextWhenReady();
}
@Override
public final void updateTrustedRoots(List<X509Certificate> trustedRoots) {
savedTrustedRoots = trustedRoots;
updateSslContextWhenReady();
}
private void updateSslContextWhenReady() {
if (isMtls()) {
if (savedKey != null && savedTrustedRoots != null) {
updateSslContext();
clearKeysAndCerts();
}
} else if (isClientSideTls()) {
if (savedTrustedRoots != null) {
updateSslContext();
clearKeysAndCerts();
}
} else if (isServerSideTls()) {
if (savedKey != null) {
updateSslContext();
clearKeysAndCerts();
}
}
}
private void clearKeysAndCerts() {
savedKey = null;
savedTrustedRoots = null;
savedCertChain = null;
}
protected final boolean isMtls() {
return certInstance != null && rootCertInstance != null;
}
protected final boolean isClientSideTls() {
return rootCertInstance != null && certInstance == null;
}
protected final boolean isServerSideTls() {
return certInstance != null && rootCertInstance == null;
}
@Override
protected final CertificateValidationContext generateCertificateValidationContext() {
return staticCertificateValidationContext;
}
@Override
public final void close() {
if (certHandle != null) {
certHandle.close();
}
if (rootCertHandle != null) {
rootCertHandle.close();
}
}
}