• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #20002

29 Sep 2025 04:21PM UTC coverage: 88.592% (+0.02%) from 88.575%
#20002

push

github

web-flow
xds: xDS based SNI setting and SAN validation (#12378)

When using xDS credentials make SNI for the Tls handshake to be
configured via xDS, rather than use the channel authority as the SNI,
and make SAN validation to be able to use the SNI sent when so
instructed via xDS.

Implements A101.

34877 of 39368 relevant lines covered (88.59%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.23
/../xds/src/main/java/io/grpc/xds/internal/security/DynamicSslContextProvider.java
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;
18

19
import static com.google.common.base.Preconditions.checkNotNull;
20

21
import com.google.common.collect.ImmutableList;
22
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateValidationContext;
23
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext;
24
import io.grpc.Internal;
25
import io.grpc.Status;
26
import io.grpc.xds.EnvoyServerProtoData.BaseTlsContext;
27
import io.netty.handler.ssl.ApplicationProtocolConfig;
28
import io.netty.handler.ssl.SslContext;
29
import io.netty.handler.ssl.SslContextBuilder;
30
import java.io.IOException;
31
import java.security.cert.CertStoreException;
32
import java.security.cert.CertificateException;
33
import java.util.AbstractMap;
34
import java.util.ArrayList;
35
import java.util.List;
36
import javax.annotation.Nullable;
37
import javax.net.ssl.X509TrustManager;
38

39
/** Base class for dynamic {@link SslContextProvider}s. */
40
@Internal
41
public abstract class DynamicSslContextProvider extends SslContextProvider {
42

43
  protected final List<Callback> pendingCallbacks = new ArrayList<>();
1✔
44
  @Nullable protected final CertificateValidationContext staticCertificateValidationContext;
45
  @Nullable protected AbstractMap.SimpleImmutableEntry<SslContext, X509TrustManager>
46
      sslContextAndTrustManager;
47

48
  protected DynamicSslContextProvider(
49
      BaseTlsContext tlsContext, CertificateValidationContext staticCertValidationContext) {
50
    super(tlsContext);
1✔
51
    this.staticCertificateValidationContext = staticCertValidationContext;
1✔
52
  }
1✔
53

54
  @Nullable
55
  public AbstractMap.SimpleImmutableEntry<SslContext, X509TrustManager>
56
      getSslContextAndTrustManager() {
57
    return sslContextAndTrustManager;
1✔
58
  }
59

60
  protected abstract CertificateValidationContext generateCertificateValidationContext();
61

62
  /** Gets a server or client side SslContextBuilder. */
63
  protected abstract AbstractMap.SimpleImmutableEntry<SslContextBuilder, X509TrustManager>
64
      getSslContextBuilderAndTrustManager(
65
          CertificateValidationContext certificateValidationContext)
66
      throws CertificateException, IOException, CertStoreException;
67

68
  // this gets called only when requested secrets are ready...
69
  protected final void updateSslContext() {
70
    try {
71
      CertificateValidationContext localCertValidationContext =
1✔
72
          generateCertificateValidationContext();
1✔
73
      AbstractMap.SimpleImmutableEntry<SslContextBuilder, X509TrustManager> sslContextBuilderAndTm =
1✔
74
          getSslContextBuilderAndTrustManager(localCertValidationContext);
1✔
75
      CommonTlsContext commonTlsContext = getCommonTlsContext();
1✔
76
      if (commonTlsContext != null && commonTlsContext.getAlpnProtocolsCount() > 0) {
1✔
77
        List<String> alpnList = commonTlsContext.getAlpnProtocolsList();
×
78
        ApplicationProtocolConfig apn =
×
79
            new ApplicationProtocolConfig(
80
                ApplicationProtocolConfig.Protocol.ALPN,
81
                ApplicationProtocolConfig.SelectorFailureBehavior.NO_ADVERTISE,
82
                ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT,
83
                alpnList);
84
        sslContextBuilderAndTm.getKey().applicationProtocolConfig(apn);
×
85
      }
86
      List<Callback> pendingCallbacksCopy;
87
      AbstractMap.SimpleImmutableEntry<SslContext, X509TrustManager>
88
          sslContextAndExtendedX09TrustManagerCopy;
89
      synchronized (pendingCallbacks) {
1✔
90
        sslContextAndTrustManager = new AbstractMap.SimpleImmutableEntry<>(
1✔
91
            sslContextBuilderAndTm.getKey().build(), sslContextBuilderAndTm.getValue());
1✔
92
        sslContextAndExtendedX09TrustManagerCopy = sslContextAndTrustManager;
1✔
93
        pendingCallbacksCopy = clonePendingCallbacksAndClear();
1✔
94
      }
1✔
95
      makePendingCallbacks(sslContextAndExtendedX09TrustManagerCopy, pendingCallbacksCopy);
1✔
96
    } catch (Exception e) {
1✔
97
      onError(Status.fromThrowable(e));
1✔
98
      throw new RuntimeException(e);
1✔
99
    }
1✔
100
  }
1✔
101

102
  protected final void callPerformCallback(
103
          Callback callback,
104
          final AbstractMap.SimpleImmutableEntry<SslContext,X509TrustManager> sslContextAndTmCopy) {
105
    performCallback(
1✔
106
        new SslContextGetter() {
1✔
107
          @Override
108
          public AbstractMap.SimpleImmutableEntry<SslContext,X509TrustManager> get() {
109
            return sslContextAndTmCopy;
1✔
110
          }
111
        },
112
        callback
113
    );
114
  }
1✔
115

116
  @Override
117
  public final void addCallback(Callback callback) {
118
    checkNotNull(callback, "callback");
1✔
119
    // if there is a computed sslContext just send it
120
    AbstractMap.SimpleImmutableEntry<SslContext, X509TrustManager> sslContextCopy = null;
1✔
121
    synchronized (pendingCallbacks) {
1✔
122
      if (sslContextAndTrustManager != null) {
1✔
123
        sslContextCopy = sslContextAndTrustManager;
1✔
124
      } else {
125
        pendingCallbacks.add(callback);
1✔
126
      }
127
    }
1✔
128
    if (sslContextCopy != null) {
1✔
129
      callPerformCallback(callback, sslContextCopy);
1✔
130
    }
131
  }
1✔
132

133
  private final void makePendingCallbacks(
134
      AbstractMap.SimpleImmutableEntry<SslContext, X509TrustManager>
135
          sslContextAndExtendedX509TrustManagerCopy,
136
      List<Callback> pendingCallbacksCopy) {
137
    for (Callback callback : pendingCallbacksCopy) {
1✔
138
      callPerformCallback(callback, sslContextAndExtendedX509TrustManagerCopy);
1✔
139
    }
1✔
140
  }
1✔
141

142
  /** Propagates error to all the callback receivers. */
143
  public final void onError(Status error) {
144
    for (Callback callback : clonePendingCallbacksAndClear()) {
1✔
145
      callback.onException(error.asException());
1✔
146
    }
1✔
147
  }
1✔
148

149
  private List<Callback> clonePendingCallbacksAndClear() {
150
    synchronized (pendingCallbacks) {
1✔
151
      List<Callback> copy = ImmutableList.copyOf(pendingCallbacks);
1✔
152
      pendingCallbacks.clear();
1✔
153
      return copy;
1✔
154
    }
155
  }
156
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc