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

grpc / grpc-java / #19950

19 Aug 2025 04:11PM UTC coverage: 88.555% (-0.005%) from 88.56%
#19950

push

github

web-flow
xds: xdsClient caches transient error for new watchers (#12262)

34695 of 39179 relevant lines covered (88.56%)

0.89 hits per line

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

57.89
/../netty/src/main/java/io/grpc/netty/GrpcSslContexts.java
1
/*
2
 * Copyright 2015 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.netty;
18

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

21
import com.google.errorprone.annotations.CanIgnoreReturnValue;
22
import io.grpc.ExperimentalApi;
23
import io.grpc.internal.ConscryptLoader;
24
import io.netty.handler.codec.http2.Http2SecurityUtil;
25
import io.netty.handler.ssl.ApplicationProtocolConfig;
26
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
27
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
28
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
29
import io.netty.handler.ssl.OpenSsl;
30
import io.netty.handler.ssl.SslContextBuilder;
31
import io.netty.handler.ssl.SslProvider;
32
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
33
import java.io.File;
34
import java.io.InputStream;
35
import java.security.Provider;
36
import java.security.Security;
37
import java.util.Arrays;
38
import java.util.Collections;
39
import java.util.List;
40
import java.util.logging.Level;
41
import java.util.logging.Logger;
42

43
/**
44
 * Utility for configuring SslContext for gRPC.
45
 */
46
@SuppressWarnings("deprecation")
47
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1784")
48
public class GrpcSslContexts {
49
  private static final Logger logger = Logger.getLogger(GrpcSslContexts.class.getName());
1✔
50

51
  private GrpcSslContexts() {}
52

53
  // The "h2" string identifies HTTP/2 when used over TLS
54
  private static final String HTTP2_VERSION = "h2";
55

56
  /*
57
   * List of ALPN/NPN protocols in order of preference.
58
   */
59
  private static final List<String> NEXT_PROTOCOL_VERSIONS =
1✔
60
      Collections.unmodifiableList(Arrays.asList(HTTP2_VERSION));
1✔
61

62
  /*
63
   * These configs use ACCEPT due to limited support in OpenSSL.  Actual protocol enforcement is
64
   * done in ProtocolNegotiators.
65
   */
66
  private static final ApplicationProtocolConfig ALPN = new ApplicationProtocolConfig(
1✔
67
      Protocol.ALPN,
68
      SelectorFailureBehavior.NO_ADVERTISE,
69
      SelectedListenerFailureBehavior.ACCEPT,
70
      NEXT_PROTOCOL_VERSIONS);
71

72
  private static final ApplicationProtocolConfig NPN = new ApplicationProtocolConfig(
1✔
73
      Protocol.NPN,
74
      SelectorFailureBehavior.NO_ADVERTISE,
75
      SelectedListenerFailureBehavior.ACCEPT,
76
      NEXT_PROTOCOL_VERSIONS);
77

78
  private static final ApplicationProtocolConfig NPN_AND_ALPN = new ApplicationProtocolConfig(
1✔
79
      Protocol.NPN_AND_ALPN,
80
      SelectorFailureBehavior.NO_ADVERTISE,
81
      SelectedListenerFailureBehavior.ACCEPT,
82
      NEXT_PROTOCOL_VERSIONS);
83

84
  private static final String SUN_PROVIDER_NAME = "SunJSSE";
85
  private static final String IBM_PROVIDER_NAME = "IBMJSSE2";
86
  private static final String OPENJSSE_PROVIDER_NAME = "OpenJSSE";
87
  private static final String BCJSSE_PROVIDER_NAME = "BCJSSE";
88

89
  /**
90
   * Creates an SslContextBuilder with ciphers and APN appropriate for gRPC.
91
   *
92
   * @see SslContextBuilder#forClient()
93
   * @see #configure(SslContextBuilder)
94
   */
95
  public static SslContextBuilder forClient() {
96
    return configure(SslContextBuilder.forClient());
1✔
97
  }
98

99
  /**
100
   * Creates an SslContextBuilder with ciphers and APN appropriate for gRPC.
101
   *
102
   * @see SslContextBuilder#forServer(File, File)
103
   * @see #configure(SslContextBuilder)
104
   */
105
  public static SslContextBuilder forServer(File keyCertChainFile, File keyFile) {
106
    return configure(SslContextBuilder.forServer(keyCertChainFile, keyFile));
×
107
  }
108

109
  /**
110
   * Creates an SslContextBuilder with ciphers and APN appropriate for gRPC.
111
   *
112
   * @see SslContextBuilder#forServer(File, File, String)
113
   * @see #configure(SslContextBuilder)
114
   */
115
  public static SslContextBuilder forServer(
116
      File keyCertChainFile, File keyFile, String keyPassword) {
117
    return configure(SslContextBuilder.forServer(keyCertChainFile, keyFile, keyPassword));
×
118
  }
119

120
  /**
121
   * Creates an SslContextBuilder with ciphers and APN appropriate for gRPC.
122
   *
123
   * @see SslContextBuilder#forServer(InputStream, InputStream)
124
   * @see #configure(SslContextBuilder)
125
   */
126
  public static SslContextBuilder forServer(InputStream keyCertChain, InputStream key) {
127
    return configure(SslContextBuilder.forServer(keyCertChain, key));
1✔
128
  }
129

130
  /**
131
   * Creates an SslContextBuilder with ciphers and APN appropriate for gRPC.
132
   *
133
   * @see SslContextBuilder#forServer(InputStream, InputStream, String)
134
   * @see #configure(SslContextBuilder)
135
   */
136
  public static SslContextBuilder forServer(
137
      InputStream keyCertChain, InputStream key, String keyPassword) {
138
    return configure(SslContextBuilder.forServer(keyCertChain, key, keyPassword));
1✔
139
  }
140

141
  /**
142
   * Set ciphers and APN appropriate for gRPC. Precisely what is set is permitted to change, so if
143
   * an application requires particular settings it should override the options set here.
144
   */
145
  @CanIgnoreReturnValue
146
  public static SslContextBuilder configure(SslContextBuilder builder) {
147
    return configure(builder, defaultSslProvider());
1✔
148
  }
149

150
  /**
151
   * Set ciphers and APN appropriate for gRPC. Precisely what is set is permitted to change, so if
152
   * an application requires particular settings it should override the options set here.
153
   */
154
  @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1784")
155
  @CanIgnoreReturnValue
156
  public static SslContextBuilder configure(SslContextBuilder builder, SslProvider provider) {
157
    switch (provider) {
1✔
158
      case JDK: {
159
        Provider jdkProvider = findJdkProvider();
1✔
160
        if (jdkProvider == null) {
1✔
161
          throw new IllegalArgumentException(
×
162
              "Could not find Jetty NPN/ALPN or Conscrypt as installed JDK providers");
163
        }
164
        return configure(builder, jdkProvider);
1✔
165
      }
166
      case OPENSSL: {
167
        ApplicationProtocolConfig apc;
168
        if (OpenSsl.isAlpnSupported()) {
1✔
169
          apc = NPN_AND_ALPN;
1✔
170
        } else {
171
          apc = NPN;
×
172
        }
173
        return builder
1✔
174
            .sslProvider(SslProvider.OPENSSL)
1✔
175
            .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
1✔
176
            .applicationProtocolConfig(apc);
1✔
177
      }
178
      default:
179
        throw new IllegalArgumentException("Unsupported provider: " + provider);
×
180
    }
181
  }
182

183
  /**
184
   * Set ciphers and APN appropriate for gRPC. Precisely what is set is permitted to change, so if
185
   * an application requires particular settings it should override the options set here.
186
   */
187
  @CanIgnoreReturnValue
188
  public static SslContextBuilder configure(SslContextBuilder builder, Provider jdkProvider) {
189
    ApplicationProtocolConfig apc;
190
    if (SUN_PROVIDER_NAME.equals(jdkProvider.getName())) {
1✔
191
      // Jetty ALPN/NPN only supports one of NPN or ALPN
192
      if (JettyTlsUtil.isJettyAlpnConfigured()) {
1✔
193
        apc = ALPN;
×
194
      } else if (JettyTlsUtil.isJettyNpnConfigured()) {
1✔
195
        apc = NPN;
×
196
      } else if (JettyTlsUtil.isJava9AlpnAvailable()) {
1✔
197
        apc = ALPN;
1✔
198
      } else {
199
        throw new IllegalArgumentException(
×
200
            jdkProvider.getName() + " selected, but Java 9+ and Jetty NPN/ALPN unavailable");
×
201
      }
202
    } else if (IBM_PROVIDER_NAME.equals(jdkProvider.getName())
1✔
203
        || OPENJSSE_PROVIDER_NAME.equals(jdkProvider.getName())
1✔
204
        || BCJSSE_PROVIDER_NAME.equals(jdkProvider.getName())) {
1✔
205
      if (JettyTlsUtil.isJava9AlpnAvailable()) {
×
206
        apc = ALPN;
×
207
      } else {
208
        throw new IllegalArgumentException(
×
209
            jdkProvider.getName() + " selected, but Java 9+ ALPN unavailable");
×
210
      }
211
    } else if (ConscryptLoader.isConscrypt(jdkProvider)) {
1✔
212
      apc = ALPN;
1✔
213
      // TODO: Conscrypt triggers failures in the TrustManager.
214
      // https://github.com/grpc/grpc-java/issues/7765
215
      builder.protocols("TLSv1.2");
1✔
216
    } else {
217
      throw new IllegalArgumentException("Unknown provider; can't configure: " + jdkProvider);
×
218
    }
219
    return builder
1✔
220
        .sslProvider(SslProvider.JDK)
1✔
221
        .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
1✔
222
        .applicationProtocolConfig(apc)
1✔
223
        .sslContextProvider(jdkProvider);
1✔
224
  }
225

226
  /**
227
   * Returns OpenSSL if available, otherwise returns the JDK provider.
228
   */
229
  private static SslProvider defaultSslProvider() {
230
    if (OpenSsl.isAvailable()) {
1✔
231
      logger.log(Level.FINE, "Selecting OPENSSL");
1✔
232
      return SslProvider.OPENSSL;
1✔
233
    }
234
    Provider provider = findJdkProvider();
1✔
235
    if (provider != null) {
1✔
236
      logger.log(Level.FINE, "Selecting JDK with provider {0}", provider);
1✔
237
      return SslProvider.JDK;
1✔
238
    }
239
    logger.log(Level.INFO, "Java 9 ALPN API unavailable (this may be normal)");
×
240
    logger.log(Level.INFO, "netty-tcnative unavailable (this may be normal)",
×
241
        OpenSsl.unavailabilityCause());
×
242
    logger.log(Level.INFO, "Conscrypt not found (this may be normal)",
×
243
        ConscryptHolder.UNAVAILABILITY_CAUSE);
244
    logger.log(Level.INFO, "Jetty ALPN unavailable (this may be normal)",
×
245
        JettyTlsUtil.getJettyAlpnUnavailabilityCause());
×
246
    throw new IllegalStateException(
×
247
        "Could not find TLS ALPN provider; "
248
        + "no working netty-tcnative, Conscrypt, or Jetty NPN/ALPN available");
249
  }
250

251
  private static Provider findJdkProvider() {
252
    for (Provider provider : Security.getProviders("SSLContext.TLS")) {
1✔
253
      if (SUN_PROVIDER_NAME.equals(provider.getName())) {
1✔
254
        if (JettyTlsUtil.isJettyAlpnConfigured()
1✔
255
            || JettyTlsUtil.isJettyNpnConfigured()
1✔
256
            || JettyTlsUtil.isJava9AlpnAvailable()) {
1✔
257
          return provider;
1✔
258
        }
259
      } else if (IBM_PROVIDER_NAME.equals(provider.getName())
×
260
          || OPENJSSE_PROVIDER_NAME.equals(provider.getName())
×
261
          || BCJSSE_PROVIDER_NAME.equals(provider.getName())) {
×
262
        if (JettyTlsUtil.isJava9AlpnAvailable()) {
×
263
          return provider;
×
264
        }
265
      } else if (ConscryptLoader.isConscrypt(provider)) {
×
266
        return provider;
×
267
      }
268
    }
269
    if (ConscryptHolder.PROVIDER != null) {
×
270
      return ConscryptHolder.PROVIDER;
×
271
    }
272
    return null;
×
273
  }
274

275
  @SuppressWarnings("deprecation")
276
  static void ensureAlpnAndH2Enabled(
277
      io.netty.handler.ssl.ApplicationProtocolNegotiator alpnNegotiator) {
278
    checkArgument(alpnNegotiator != null, "ALPN must be configured");
1✔
279
    checkArgument(alpnNegotiator.protocols() != null && !alpnNegotiator.protocols().isEmpty(),
1✔
280
        "ALPN must be enabled and list HTTP/2 as a supported protocol.");
281
    checkArgument(
1✔
282
        alpnNegotiator.protocols().contains(HTTP2_VERSION),
1✔
283
        "This ALPN config does not support HTTP/2. Expected %s, but got %s'.",
284
        HTTP2_VERSION,
285
        alpnNegotiator.protocols());
1✔
286
  }
1✔
287

288
  private static class ConscryptHolder {
289
    static final Provider PROVIDER;
290
    static final Throwable UNAVAILABILITY_CAUSE;
291

292
    static {
293
      Provider provider;
294
      Throwable cause;
295
      try {
296
        provider = ConscryptLoader.newProvider();
×
297
        cause = null;
×
298
      } catch (Throwable t) {
×
299
        provider = null;
×
300
        cause = t;
×
301
      }
×
302
      PROVIDER = provider;
×
303
      UNAVAILABILITY_CAUSE = cause;
×
304
    }
×
305
  }
306
}
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

© 2026 Coveralls, Inc