View Javadoc
1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://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, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  
17  package io.netty.handler.ssl;
18  
19  import io.netty.buffer.ByteBuf;
20  import io.netty.buffer.ByteBufAllocator;
21  import io.netty.buffer.UnpooledByteBufAllocator;
22  import io.netty.internal.tcnative.Buffer;
23  import io.netty.internal.tcnative.Library;
24  import io.netty.internal.tcnative.SSL;
25  import io.netty.internal.tcnative.SSLContext;
26  import io.netty.util.CharsetUtil;
27  import io.netty.util.LeakPresenceDetector;
28  import io.netty.util.ReferenceCountUtil;
29  import io.netty.util.ReferenceCounted;
30  import io.netty.util.internal.EmptyArrays;
31  import io.netty.util.internal.NativeLibraryLoader;
32  import io.netty.util.internal.PlatformDependent;
33  import io.netty.util.internal.StringUtil;
34  import io.netty.util.internal.SystemPropertyUtil;
35  import io.netty.util.internal.logging.InternalLogger;
36  import io.netty.util.internal.logging.InternalLoggerFactory;
37  
38  import java.io.ByteArrayInputStream;
39  import java.nio.ByteBuffer;
40  import java.security.cert.CertificateException;
41  import java.security.cert.X509Certificate;
42  import java.util.ArrayList;
43  import java.util.Arrays;
44  import java.util.Collection;
45  import java.util.Collections;
46  import java.util.HashSet;
47  import java.util.Iterator;
48  import java.util.LinkedHashSet;
49  import java.util.List;
50  import java.util.Set;
51  
52  import static io.netty.handler.ssl.SslUtils.DEFAULT_CIPHER_SUITES;
53  import static io.netty.handler.ssl.SslUtils.PROBING_CERT;
54  import static io.netty.handler.ssl.SslUtils.PROBING_KEY;
55  import static io.netty.handler.ssl.SslUtils.TLSV13_CIPHERS;
56  import static io.netty.handler.ssl.SslUtils.TLSV13_CIPHER_SUITES;
57  import static io.netty.handler.ssl.SslUtils.addIfSupported;
58  import static io.netty.handler.ssl.SslUtils.isTLSv13Cipher;
59  import static io.netty.handler.ssl.SslUtils.useFallbackCiphersIfDefaultIsEmpty;
60  
61  /**
62   * Tells if <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
63   * are available.
64   */
65  public final class OpenSsl {
66  
67      private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class);
68      private static final Throwable UNAVAILABILITY_CAUSE;
69      static final List<String> DEFAULT_CIPHERS;
70      static final Set<String> AVAILABLE_CIPHER_SUITES;
71      private static final Set<String> AVAILABLE_OPENSSL_CIPHER_SUITES;
72      private static final Set<String> AVAILABLE_JAVA_CIPHER_SUITES;
73      private static final boolean SUPPORTS_KEYMANAGER_FACTORY;
74      private static final boolean USE_KEYMANAGER_FACTORY;
75      private static final boolean SUPPORTS_OCSP;
76      private static final boolean TLSV13_SUPPORTED;
77      private static final boolean IS_BORINGSSL;
78      private static final boolean IS_AWSLC;
79      private static final Set<String> CLIENT_DEFAULT_PROTOCOLS;
80      private static final Set<String> SERVER_DEFAULT_PROTOCOLS;
81  
82      private static final int SSL_V2_HELLO = 1;
83      private static final int SSL_V2 = 1 << 1;
84      private static final int SSL_V3 = 1 << 2;
85      private static final int TLS_V1 = 1 << 3;
86      private static final int TLS_V1_1 = 1 << 4;
87      private static final int TLS_V1_2 = 1 << 5;
88      private static final int TLS_V1_3 = 1 << 6;
89      private static final int supportedProtocolsPacked;
90  
91      static final String[] EXTRA_SUPPORTED_TLS_1_3_CIPHERS;
92      static final String EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING;
93      static final String[] NAMED_GROUPS;
94  
95      static final boolean JAVAX_CERTIFICATE_CREATION_SUPPORTED;
96  
97      // Use default that is supported in java 11 and earlier and also in OpenSSL / BoringSSL.
98      // See https://github.com/netty/netty-tcnative/issues/567
99      // See https://www.java.com/en/configure_crypto.html for ordering
100     private static final String[] DEFAULT_NAMED_GROUPS = { "x25519", "secp256r1", "secp384r1", "secp521r1" };
101 
102     static {
103         Throwable cause = null;
104 
105         if (SystemPropertyUtil.getBoolean("io.netty.handler.ssl.noOpenSsl", false)) {
106             cause = new UnsupportedOperationException(
107                     "OpenSSL was explicit disabled with -Dio.netty.handler.ssl.noOpenSsl=true");
108 
109             logger.debug(
110                     "netty-tcnative explicit disabled; " +
111                             OpenSslEngine.class.getSimpleName() + " will be unavailable.", cause);
112         } else {
113             // Test if netty-tcnative is in the classpath first.
114             try {
115                 Class.forName("io.netty.internal.tcnative.SSLContext", false,
116                         PlatformDependent.getClassLoader(OpenSsl.class));
117             } catch (ClassNotFoundException t) {
118                 cause = t;
119                 logger.debug(
120                         "netty-tcnative not in the classpath; " +
121                                 OpenSslEngine.class.getSimpleName() + " will be unavailable.");
122             }
123 
124             // If in the classpath, try to load the native library and initialize netty-tcnative.
125             if (cause == null) {
126                 try {
127                     // The JNI library was not already loaded. Load it now.
128                     loadTcNative();
129                 } catch (Throwable t) {
130                     cause = t;
131                     logger.debug(
132                             "Failed to load netty-tcnative; " +
133                                     OpenSslEngine.class.getSimpleName() + " will be unavailable, unless the " +
134                                     "application has already loaded the symbols by some other means. " +
135                                     "See https://netty.io/wiki/forked-tomcat-native.html for more information.", t);
136                 }
137 
138                 try {
139                     String engine = SystemPropertyUtil.get("io.netty.handler.ssl.openssl.engine", null);
140                     if (engine == null) {
141                         logger.debug("Initialize netty-tcnative using engine: 'default'");
142                     } else {
143                         logger.debug("Initialize netty-tcnative using engine: '{}'", engine);
144                     }
145                     initializeTcNative(engine);
146 
147                     // The library was initialized successfully. If loading the library failed above,
148                     // reset the cause now since it appears that the library was loaded by some other
149                     // means.
150                     cause = null;
151                 } catch (Throwable t) {
152                     if (cause == null) {
153                         cause = t;
154                     }
155                     logger.debug(
156                             "Failed to initialize netty-tcnative; " +
157                                     OpenSslEngine.class.getSimpleName() + " will be unavailable. " +
158                                     "See https://netty.io/wiki/forked-tomcat-native.html for more information.", t);
159                 }
160             }
161         }
162 
163         UNAVAILABILITY_CAUSE = cause;
164         CLIENT_DEFAULT_PROTOCOLS = defaultProtocols("jdk.tls.client.protocols");
165         SERVER_DEFAULT_PROTOCOLS = defaultProtocols("jdk.tls.server.protocols");
166 
167         if (cause == null) {
168             logger.debug("netty-tcnative using native library: {}", SSL.versionString());
169 
170             final List<String> defaultCiphers = new ArrayList<>();
171             final Set<String> availableOpenSslCipherSuites = new LinkedHashSet<>(128);
172             boolean supportsKeyManagerFactory = false;
173             boolean useKeyManagerFactory = false;
174             boolean tlsv13Supported = false;
175             String[] namedGroups = DEFAULT_NAMED_GROUPS;
176             Set<String> defaultConvertedNamedGroups = new LinkedHashSet<>(namedGroups.length);
177             for (String group : namedGroups) {
178                 defaultConvertedNamedGroups.add(GroupsConverter.toOpenSsl(group));
179             }
180 
181             IS_BORINGSSL = "BoringSSL".equals(versionString());
182             IS_AWSLC = versionString().startsWith("AWS-LC");
183             if (IS_BORINGSSL) {
184                 EXTRA_SUPPORTED_TLS_1_3_CIPHERS = new String [] { "TLS_AES_128_GCM_SHA256",
185                         "TLS_AES_256_GCM_SHA384" ,
186                         "TLS_CHACHA20_POLY1305_SHA256" };
187 
188                 StringBuilder ciphersBuilder = new StringBuilder(128);
189                 for (String cipher: EXTRA_SUPPORTED_TLS_1_3_CIPHERS) {
190                     ciphersBuilder.append(cipher).append(":");
191                 }
192                 ciphersBuilder.setLength(ciphersBuilder.length() - 1);
193                 EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING = ciphersBuilder.toString();
194             }  else {
195                 EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS;
196                 EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING = StringUtil.EMPTY_STRING;
197             }
198 
199             try {
200                 final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER);
201 
202                 // Let's filter out any group that is not supported from the default.
203                 Iterator<String> defaultGroupsIter = defaultConvertedNamedGroups.iterator();
204                 while (defaultGroupsIter.hasNext()) {
205                     if (!SSLContext.setCurvesList(sslCtx, defaultGroupsIter.next())) {
206                         // Not supported, let's remove it. This could for example be the case if we use
207                         // fips and the configure group is not supported when using FIPS.
208                         // See https://github.com/netty/netty-tcnative/issues/883
209                         defaultGroupsIter.remove();
210 
211                         // Clear the error as otherwise we might fail later.
212                         SSL.clearError();
213                     }
214                 }
215                 namedGroups = defaultConvertedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS);
216 
217                 long certBio = 0;
218                 long keyBio = 0;
219                 long cert = 0;
220                 long key = 0;
221                 try {
222                     // As we delegate to the KeyManager / TrustManager of the JDK we need to ensure it can actually
223                     // handle TLSv13 as otherwise we may see runtime exceptions
224                     if (SslProvider.isTlsv13Supported(SslProvider.JDK)) {
225                         try {
226                             StringBuilder tlsv13Ciphers = new StringBuilder();
227 
228                             for (String cipher : TLSV13_CIPHERS) {
229                                 String converted = CipherSuiteConverter.toOpenSsl(cipher, IS_BORINGSSL);
230                                 if (converted != null) {
231                                     tlsv13Ciphers.append(converted).append(':');
232                                 }
233                             }
234                             if (tlsv13Ciphers.length() == 0) {
235                                 tlsv13Supported = false;
236                             } else {
237                                 tlsv13Ciphers.setLength(tlsv13Ciphers.length() - 1);
238                                 SSLContext.setCipherSuite(sslCtx, tlsv13Ciphers.toString(), true);
239                                 tlsv13Supported = true;
240                             }
241 
242                         } catch (Exception ignore) {
243                             tlsv13Supported = false;
244                             SSL.clearError();
245                         }
246                     }
247 
248                     SSLContext.setCipherSuite(sslCtx, "ALL", false);
249 
250                     final long ssl = SSL.newSSL(sslCtx, true);
251                     try {
252                         for (String c: SSL.getCiphers(ssl)) {
253                             // Filter out bad input.
254                             if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c) ||
255                                 // Filter out TLSv1.3 ciphers if not supported.
256                                 !tlsv13Supported && isTLSv13Cipher(c)) {
257                                 continue;
258                             }
259                             availableOpenSslCipherSuites.add(c);
260                         }
261                         if (IS_BORINGSSL) {
262                             // Currently BoringSSL does not include these when calling SSL.getCiphers() even when these
263                             // are supported.
264                             Collections.addAll(availableOpenSslCipherSuites, EXTRA_SUPPORTED_TLS_1_3_CIPHERS);
265                             Collections.addAll(availableOpenSslCipherSuites,
266                                                "AEAD-AES128-GCM-SHA256",
267                                                "AEAD-AES256-GCM-SHA384",
268                                                "AEAD-CHACHA20-POLY1305-SHA256");
269                         }
270 
271                         PemEncoded privateKey = PemPrivateKey.valueOf(PROBING_KEY.getBytes(CharsetUtil.US_ASCII));
272                         try {
273                             // Let's check if we can set a callback, which may not work if the used OpenSSL version
274                             // is to old.
275                             SSLContext.setCertificateCallback(sslCtx, null);
276 
277                             X509Certificate certificate = selfSignedCertificate();
278                             certBio = LeakPresenceDetector.staticInitializer(() -> {
279                                 try {
280                                     return ReferenceCountedOpenSslContext.toBIO(ByteBufAllocator.DEFAULT, certificate);
281                                 } catch (Exception e) {
282                                     // go to catch outside lambda
283                                     PlatformDependent.throwException(e);
284                                     throw new AssertionError(e);
285                                 }
286                             });
287                             cert = SSL.parseX509Chain(certBio);
288 
289                             keyBio = LeakPresenceDetector.staticInitializer(() -> {
290                                 try {
291                                     return ReferenceCountedOpenSslContext.toBIO(
292                                             UnpooledByteBufAllocator.DEFAULT, privateKey.retain());
293                                 } catch (Exception e) {
294                                     // go to catch outside lambda
295                                     PlatformDependent.throwException(e);
296                                     throw new AssertionError(e);
297                                 }
298                             });
299                             key = SSL.parsePrivateKey(keyBio, null);
300 
301                             SSL.setKeyMaterial(ssl, cert, key);
302                             supportsKeyManagerFactory = true;
303                             try {
304                                 boolean propertySet = SystemPropertyUtil.contains(
305                                         "io.netty.handler.ssl.openssl.useKeyManagerFactory");
306                                 if (!(IS_BORINGSSL || IS_AWSLC)) {
307                                     useKeyManagerFactory = SystemPropertyUtil.getBoolean(
308                                             "io.netty.handler.ssl.openssl.useKeyManagerFactory", true);
309 
310                                     if (propertySet) {
311                                         logger.info("System property " +
312                                                 "'io.netty.handler.ssl.openssl.useKeyManagerFactory'" +
313                                                 " is deprecated and so will be ignored in the future");
314                                     }
315                                 } else {
316                                     useKeyManagerFactory = true;
317                                     if (propertySet) {
318                                         logger.info("System property " +
319                                                 "'io.netty.handler.ssl.openssl.useKeyManagerFactory'" +
320                                                 " is deprecated and will be ignored when using BoringSSL or AWS-LC");
321                                     }
322                                 }
323                             } catch (Throwable ignore) {
324                                 logger.debug("Failed to get useKeyManagerFactory system property.");
325                             }
326                         } catch (Exception e) {
327                             logger.debug("KeyManagerFactory not supported", e);
328                             SSL.clearError();
329                         } finally {
330                             privateKey.release();
331                         }
332                     } finally {
333                         SSL.freeSSL(ssl);
334                         if (certBio != 0) {
335                             SSL.freeBIO(certBio);
336                         }
337                         if (keyBio != 0) {
338                             SSL.freeBIO(keyBio);
339                         }
340                         if (cert != 0) {
341                             SSL.freeX509Chain(cert);
342                         }
343                         if (key != 0) {
344                             SSL.freePrivateKey(key);
345                         }
346                     }
347 
348                     String groups = SystemPropertyUtil.get("jdk.tls.namedGroups", null);
349                     if (groups != null) {
350                         String[] nGroups = groups.split(",");
351                         Set<String> supportedNamedGroups = new LinkedHashSet<>(nGroups.length);
352                         Set<String> supportedConvertedNamedGroups = new LinkedHashSet<>(nGroups.length);
353 
354                         Set<String> unsupportedNamedGroups = new LinkedHashSet<>();
355                         for (String namedGroup : nGroups) {
356                             String converted = GroupsConverter.toOpenSsl(namedGroup);
357                             if (SSLContext.setCurvesList(sslCtx, converted)) {
358                                 supportedConvertedNamedGroups.add(converted);
359                                 supportedNamedGroups.add(namedGroup);
360                             } else {
361                                 unsupportedNamedGroups.add(namedGroup);
362 
363                                 // Clear the error as otherwise we might fail later.
364                                 SSL.clearError();
365                             }
366                         }
367 
368                         if (supportedNamedGroups.isEmpty()) {
369                             namedGroups = defaultConvertedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS);
370                             logger.info("All configured namedGroups are not supported: {}. Use default: {}.",
371                                     Arrays.toString(unsupportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS)),
372                                     Arrays.toString(DEFAULT_NAMED_GROUPS));
373                         } else {
374                             String[] groupArray = supportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS);
375                             if (unsupportedNamedGroups.isEmpty()) {
376                                 logger.info("Using configured namedGroups -D 'jdk.tls.namedGroup': {} ",
377                                         Arrays.toString(groupArray));
378                             } else {
379                                 logger.info("Using supported configured namedGroups: {}. Unsupported namedGroups: {}. ",
380                                         Arrays.toString(groupArray),
381                                         Arrays.toString(unsupportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS)));
382                             }
383                             namedGroups = supportedConvertedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS);
384                         }
385                     } else {
386                         namedGroups = defaultConvertedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS);
387                     }
388                 } finally {
389                     SSLContext.free(sslCtx);
390                 }
391             } catch (Exception e) {
392                 logger.warn("Failed to get the list of available OpenSSL cipher suites.", e);
393             }
394             NAMED_GROUPS = namedGroups;
395             AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites);
396             final Set<String> availableJavaCipherSuites = new LinkedHashSet<>(
397                     AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2);
398             for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) {
399                 // Included converted but also openssl cipher name
400                 if (!isTLSv13Cipher(cipher)) {
401                     final String tlsConversion = CipherSuiteConverter.toJava(cipher, "TLS");
402                     if (tlsConversion != null) {
403                         availableJavaCipherSuites.add(tlsConversion);
404                     }
405                     final String sslConversion = CipherSuiteConverter.toJava(cipher, "SSL");
406                     if (sslConversion != null) {
407                         availableJavaCipherSuites.add(sslConversion);
408                     }
409                 } else {
410                     // TLSv1.3 ciphers have the correct format.
411                     availableJavaCipherSuites.add(cipher);
412                 }
413             }
414 
415             addIfSupported(availableJavaCipherSuites, defaultCiphers, DEFAULT_CIPHER_SUITES);
416             addIfSupported(availableJavaCipherSuites, defaultCiphers, TLSV13_CIPHER_SUITES);
417             // Also handle the extra supported ciphers as these will contain some more stuff on BoringSSL.
418             addIfSupported(availableJavaCipherSuites, defaultCiphers, EXTRA_SUPPORTED_TLS_1_3_CIPHERS);
419 
420             useFallbackCiphersIfDefaultIsEmpty(defaultCiphers, availableJavaCipherSuites);
421             DEFAULT_CIPHERS = Collections.unmodifiableList(defaultCiphers);
422 
423             AVAILABLE_JAVA_CIPHER_SUITES = Collections.unmodifiableSet(availableJavaCipherSuites);
424 
425             final Set<String> availableCipherSuites = new LinkedHashSet<>(
426                     AVAILABLE_OPENSSL_CIPHER_SUITES.size() + AVAILABLE_JAVA_CIPHER_SUITES.size());
427             availableCipherSuites.addAll(AVAILABLE_OPENSSL_CIPHER_SUITES);
428             availableCipherSuites.addAll(AVAILABLE_JAVA_CIPHER_SUITES);
429 
430             AVAILABLE_CIPHER_SUITES = availableCipherSuites;
431             SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory;
432             USE_KEYMANAGER_FACTORY = useKeyManagerFactory;
433 
434             // Seems like there is no way to explicitly disable SSLv2Hello in openssl so it is always enabled
435             int supportedProtocolsPackedTemp = 0;
436             supportedProtocolsPackedTemp |= SSL_V2_HELLO;
437             if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2, SSL.SSL_OP_NO_SSLv2)) {
438                 supportedProtocolsPackedTemp |= SSL_V2;
439             }
440             if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3, SSL.SSL_OP_NO_SSLv3)) {
441                 supportedProtocolsPackedTemp |= SSL_V3;
442             }
443             if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1, SSL.SSL_OP_NO_TLSv1)) {
444                 supportedProtocolsPackedTemp |= TLS_V1;
445             }
446             if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1, SSL.SSL_OP_NO_TLSv1_1)) {
447                 supportedProtocolsPackedTemp |= TLS_V1_1;
448             }
449             if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_OP_NO_TLSv1_2)) {
450                 supportedProtocolsPackedTemp |= TLS_V1_2;
451             }
452 
453             // This is only supported by java8u272 and later.
454             if (tlsv13Supported && doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_3, SSL.SSL_OP_NO_TLSv1_3)) {
455                 supportedProtocolsPackedTemp |= TLS_V1_3;
456                 TLSV13_SUPPORTED = true;
457             } else {
458                 TLSV13_SUPPORTED = false;
459             }
460 
461             supportedProtocolsPacked = supportedProtocolsPackedTemp;
462             SUPPORTS_OCSP = doesSupportOcsp();
463 
464             if (logger.isDebugEnabled()) {
465                 logger.debug("Supported protocols (OpenSSL): {} ", unpackSupportedProtocols());
466                 logger.debug("Default cipher suites (OpenSSL): {}", DEFAULT_CIPHERS);
467             }
468 
469             // Check if we can create a javax.security.cert.X509Certificate from our cert. This might fail on
470             // JDK17 and above. In this case we will later throw an UnsupportedOperationException if someone
471             // tries to access these via SSLSession. See https://github.com/netty/netty/issues/13560.
472             boolean javaxCertificateCreationSupported;
473             try {
474                 javax.security.cert.X509Certificate.getInstance(PROBING_CERT.getBytes(CharsetUtil.US_ASCII));
475                 javaxCertificateCreationSupported = true;
476             } catch (javax.security.cert.CertificateException ex) {
477                 javaxCertificateCreationSupported = false;
478             }
479             JAVAX_CERTIFICATE_CREATION_SUPPORTED = javaxCertificateCreationSupported;
480         } else {
481             DEFAULT_CIPHERS = Collections.emptyList();
482             AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet();
483             AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet();
484             AVAILABLE_CIPHER_SUITES = Collections.emptySet();
485             SUPPORTS_KEYMANAGER_FACTORY = false;
486             USE_KEYMANAGER_FACTORY = false;
487             SUPPORTS_OCSP = false;
488             TLSV13_SUPPORTED = false;
489             supportedProtocolsPacked = 0;
490             IS_BORINGSSL = false;
491             IS_AWSLC = false;
492             EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS;
493             EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING = StringUtil.EMPTY_STRING;
494             NAMED_GROUPS = DEFAULT_NAMED_GROUPS;
495             JAVAX_CERTIFICATE_CREATION_SUPPORTED = false;
496         }
497     }
498 
499     static String checkTls13Ciphers(InternalLogger logger, String ciphers) {
500         if (IS_BORINGSSL && !ciphers.isEmpty()) {
501             assert EXTRA_SUPPORTED_TLS_1_3_CIPHERS.length > 0;
502             Set<String> boringsslTlsv13Ciphers = new HashSet<>(EXTRA_SUPPORTED_TLS_1_3_CIPHERS.length);
503             Collections.addAll(boringsslTlsv13Ciphers, EXTRA_SUPPORTED_TLS_1_3_CIPHERS);
504             boolean ciphersNotMatch = false;
505             for (String cipher: ciphers.split(":")) {
506                 if (boringsslTlsv13Ciphers.isEmpty()) {
507                     ciphersNotMatch = true;
508                     break;
509                 }
510                 if (!boringsslTlsv13Ciphers.remove(cipher) &&
511                         !boringsslTlsv13Ciphers.remove(CipherSuiteConverter.toJava(cipher, "TLS"))) {
512                     ciphersNotMatch = true;
513                     break;
514                 }
515             }
516 
517             // Also check if there are ciphers left.
518             ciphersNotMatch |= !boringsslTlsv13Ciphers.isEmpty();
519 
520             if (ciphersNotMatch) {
521                 if (logger.isInfoEnabled()) {
522                     StringBuilder javaCiphers = new StringBuilder(128);
523                     for (String cipher : ciphers.split(":")) {
524                         javaCiphers.append(CipherSuiteConverter.toJava(cipher, "TLS")).append(":");
525                     }
526                     javaCiphers.setLength(javaCiphers.length() - 1);
527                     logger.info(
528                             "BoringSSL doesn't allow to enable or disable TLSv1.3 ciphers explicitly." +
529                                     " Provided TLSv1.3 ciphers: '{}', default TLSv1.3 ciphers that will be used: '{}'.",
530                             javaCiphers, EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING);
531                 }
532                 return EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING;
533             }
534         }
535         return ciphers;
536     }
537 
538     static boolean isSessionCacheSupported() {
539         return version() >= 0x10100000L;
540     }
541 
542     /**
543      * Returns a self-signed {@link X509Certificate} for {@code netty.io}.
544      */
545     static X509Certificate selfSignedCertificate() throws CertificateException {
546         return (X509Certificate) SslContext.X509_CERT_FACTORY.generateCertificate(
547                 new ByteArrayInputStream(PROBING_CERT.getBytes(CharsetUtil.US_ASCII))
548         );
549     }
550 
551     private static boolean doesSupportOcsp() {
552         boolean supportsOcsp = false;
553         if (version() >= 0x10002000L) {
554             long sslCtx = -1;
555             try {
556                 sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_MODE_SERVER);
557                 SSLContext.enableOcsp(sslCtx, false);
558                 supportsOcsp = true;
559             } catch (Exception ignore) {
560                 // ignore
561             } finally {
562                 if (sslCtx != -1) {
563                     SSLContext.free(sslCtx);
564                 }
565             }
566         }
567         return supportsOcsp;
568     }
569     private static boolean doesSupportProtocol(int protocol, int opt) {
570         if (opt == 0) {
571             // If the opt is 0 the protocol is not supported. This is for example the case with BoringSSL and SSLv2.
572             return false;
573         }
574         long sslCtx = -1;
575         try {
576             sslCtx = SSLContext.make(protocol, SSL.SSL_MODE_COMBINED);
577             return true;
578         } catch (Exception ignore) {
579             return false;
580         } finally {
581             if (sslCtx != -1) {
582                 SSLContext.free(sslCtx);
583             }
584         }
585     }
586 
587     /**
588      * Returns {@code true} if and only if
589      * <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support
590      * are available.
591      */
592     public static boolean isAvailable() {
593         return UNAVAILABILITY_CAUSE == null;
594     }
595 
596     /**
597      * Returns {@code true} if the used version of openssl supports
598      * <a href="https://tools.ietf.org/html/rfc7301">ALPN</a>.
599      *
600      * @deprecated use {@link SslProvider#isAlpnSupported(SslProvider)} with {@link SslProvider#OPENSSL}.
601      */
602     @Deprecated
603     public static boolean isAlpnSupported() {
604         return version() >= 0x10002000L;
605     }
606 
607     /**
608      * Returns {@code true} if the used version of OpenSSL supports OCSP stapling.
609      */
610     public static boolean isOcspSupported() {
611       return SUPPORTS_OCSP;
612     }
613 
614     /**
615      * Returns {@code true} if the used version of OpenSSL supports renegotiation.
616      * <p>
617      * Some implementations, such as BoringSSL and AWS-LC, intentionally do not support renegotiation.
618      *
619      * @return {@code true} if renegotiation is supported, otherwise {@code false}.
620      */
621     public static boolean isRenegotiationSupported() {
622         return !IS_BORINGSSL && !IS_AWSLC;
623     }
624 
625     /**
626      * Returns the version of the used available OpenSSL library or {@code -1} if {@link #isAvailable()}
627      * returns {@code false}.
628      */
629     public static int version() {
630         return isAvailable() ? SSL.version() : -1;
631     }
632 
633     /**
634      * Returns the version string of the used available OpenSSL library or {@code null} if {@link #isAvailable()}
635      * returns {@code false}.
636      */
637     public static String versionString() {
638         return isAvailable() ? SSL.versionString() : null;
639     }
640 
641     /**
642      * Ensure that <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and
643      * its OpenSSL support are available.
644      *
645      * @throws UnsatisfiedLinkError if unavailable
646      */
647     public static void ensureAvailability() {
648         if (UNAVAILABILITY_CAUSE != null) {
649             throw (Error) new UnsatisfiedLinkError(
650                     "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE);
651         }
652     }
653 
654     /**
655      * Returns the cause of unavailability of
656      * <a href="https://netty.io/wiki/forked-tomcat-native.html">{@code netty-tcnative}</a> and its OpenSSL support.
657      *
658      * @return the cause if unavailable. {@code null} if available.
659      */
660     public static Throwable unavailabilityCause() {
661         return UNAVAILABILITY_CAUSE;
662     }
663 
664     /**
665      * @deprecated use {@link #availableOpenSslCipherSuites()}
666      */
667     @Deprecated
668     public static Set<String> availableCipherSuites() {
669         return availableOpenSslCipherSuites();
670     }
671 
672     /**
673      * Returns all the available OpenSSL cipher suites.
674      * Please note that the returned array may include the cipher suites that are insecure or non-functional.
675      */
676     public static Set<String> availableOpenSslCipherSuites() {
677         return AVAILABLE_OPENSSL_CIPHER_SUITES;
678     }
679 
680     /**
681      * Returns all the available cipher suites (Java-style).
682      * Please note that the returned array may include the cipher suites that are insecure or non-functional.
683      */
684     public static Set<String> availableJavaCipherSuites() {
685         return AVAILABLE_JAVA_CIPHER_SUITES;
686     }
687 
688     /**
689      * Returns {@code true} if and only if the specified cipher suite is available in OpenSSL.
690      * Both Java-style cipher suite and OpenSSL-style cipher suite are accepted.
691      */
692     public static boolean isCipherSuiteAvailable(String cipherSuite) {
693         String converted = CipherSuiteConverter.toOpenSsl(cipherSuite, IS_BORINGSSL);
694         if (converted != null) {
695             cipherSuite = converted;
696         }
697         return AVAILABLE_OPENSSL_CIPHER_SUITES.contains(cipherSuite);
698     }
699 
700     /**
701      * Returns {@code true} if {@link javax.net.ssl.KeyManagerFactory} is supported when using OpenSSL.
702      */
703     public static boolean supportsKeyManagerFactory() {
704         return SUPPORTS_KEYMANAGER_FACTORY;
705     }
706 
707     /**
708      * Always returns {@code true} if {@link #isAvailable()} returns {@code true}.
709      *
710      * @deprecated Will be removed because hostname validation is always done by a
711      * {@link javax.net.ssl.TrustManager} implementation.
712      */
713     @Deprecated
714     public static boolean supportsHostnameValidation() {
715         return isAvailable();
716     }
717 
718     static boolean useKeyManagerFactory() {
719         return USE_KEYMANAGER_FACTORY;
720     }
721 
722     static long memoryAddress(ByteBuf buf) {
723         assert buf.isDirect();
724         if (buf.hasMemoryAddress()) {
725             return buf.memoryAddress();
726         }
727         // Use internalNioBuffer to reduce object creation.
728         // It is important to add the position as the returned ByteBuffer might be shared by multiple ByteBuf
729         // instances and so has an address that starts before the start of the ByteBuf itself.
730         ByteBuffer byteBuffer = buf.internalNioBuffer(0, buf.readableBytes());
731         return Buffer.address(byteBuffer) + byteBuffer.position();
732     }
733 
734     private OpenSsl() { }
735 
736     private static void loadTcNative() throws Exception {
737         String os = PlatformDependent.normalizedOs();
738         String arch = PlatformDependent.normalizedArch();
739 
740         Set<String> libNames = new LinkedHashSet<String>(5);
741         String staticLibName = "netty_tcnative";
742 
743         // First, try loading the platform-specific library. Platform-specific
744         // libraries will be available if using a tcnative uber jar.
745         if ("linux".equals(os)) {
746             Set<String> classifiers = PlatformDependent.normalizedLinuxClassifiers();
747             for (String classifier : classifiers) {
748                 libNames.add(staticLibName + "_" + os + '_' + arch + "_" + classifier);
749             }
750             // generic arch-dependent library
751             libNames.add(staticLibName + "_" + os + '_' + arch);
752 
753             // Fedora SSL lib so naming (libssl.so.10 vs libssl.so.1.0.0).
754             // note: should already be included from the classifiers but if not, we use this as an
755             //       additional fallback option here
756             libNames.add(staticLibName + "_" + os + '_' + arch + "_fedora");
757         } else {
758             libNames.add(staticLibName + "_" + os + '_' + arch);
759         }
760         libNames.add(staticLibName + "_" + arch);
761         libNames.add(staticLibName);
762 
763         NativeLibraryLoader.loadFirstAvailable(PlatformDependent.getClassLoader(SSLContext.class),
764             libNames.toArray(EmptyArrays.EMPTY_STRINGS));
765     }
766 
767     private static boolean initializeTcNative(String engine) throws Exception {
768         return Library.initialize("provided", engine);
769     }
770 
771     static void releaseIfNeeded(ReferenceCounted counted) {
772         if (counted.refCnt() > 0) {
773             ReferenceCountUtil.safeRelease(counted);
774         }
775     }
776 
777     static boolean isTlsv13Supported() {
778         return TLSV13_SUPPORTED;
779     }
780 
781     static boolean isOptionSupported(SslContextOption<?> option) {
782         if (isAvailable()) {
783             if (option == OpenSslContextOption.USE_TASKS ||
784                     option == OpenSslContextOption.TMP_DH_KEYLENGTH) {
785                 return true;
786             }
787             // Check for options that are only supported by BoringSSL atm.
788             if (isBoringSSL() || isAWSLC()) {
789                 return option == OpenSslContextOption.ASYNC_PRIVATE_KEY_METHOD ||
790                         option == OpenSslContextOption.PRIVATE_KEY_METHOD ||
791                         option == OpenSslContextOption.CERTIFICATE_COMPRESSION_ALGORITHMS ||
792                         option == OpenSslContextOption.TLS_FALSE_START ||
793                         option == OpenSslContextOption.MAX_CERTIFICATE_LIST_BYTES;
794             }
795         }
796         return false;
797     }
798 
799     private static Set<String> defaultProtocols(String property) {
800         String protocolsString = SystemPropertyUtil.get(property, null);
801         Set<String> protocols = new HashSet<>();
802         if (protocolsString != null) {
803             for (String proto : protocolsString.split(",")) {
804                 String p = proto.trim();
805                 protocols.add(p);
806             }
807         } else {
808             protocols.add(SslProtocols.TLS_v1_2);
809             protocols.add(SslProtocols.TLS_v1_3);
810         }
811         return protocols;
812     }
813 
814     static String[] defaultProtocols(boolean isClient) {
815         final Collection<String> defaultProtocols = isClient ? CLIENT_DEFAULT_PROTOCOLS : SERVER_DEFAULT_PROTOCOLS;
816         assert defaultProtocols != null;
817         List<String> protocols = new ArrayList<>(defaultProtocols.size());
818         for (String proto : defaultProtocols) {
819             if (isProtocolSupported(proto)) {
820                 protocols.add(proto);
821             }
822         }
823         return protocols.toArray(EmptyArrays.EMPTY_STRINGS);
824     }
825 
826     static boolean isProtocolSupported(String protocol) {
827         int bit = getProtocolBit(protocol);
828         return bit != -1 && (supportedProtocolsPacked & bit) != 0;
829     }
830 
831     private static int getProtocolBit(String protocol) {
832         if (protocol == null) {
833             return -1;
834         }
835 
836         switch (protocol) {
837             case SslProtocols.SSL_v2_HELLO:
838                 return SSL_V2_HELLO;
839             case SslProtocols.SSL_v2:
840                 return SSL_V2;
841             case SslProtocols.SSL_v3:
842                 return SSL_V3;
843             case SslProtocols.TLS_v1:
844                 return TLS_V1;
845             case SslProtocols.TLS_v1_1:
846                 return TLS_V1_1;
847             case SslProtocols.TLS_v1_2:
848                 return TLS_V1_2;
849             case SslProtocols.TLS_v1_3:
850                 return TLS_V1_3;
851             default:
852                 return -1;
853         }
854     }
855 
856     static List<String> unpackSupportedProtocols() {
857         List<String> protocols = new ArrayList<>(7);
858         if ((supportedProtocolsPacked & SSL_V2_HELLO) != 0) {
859             protocols.add(SslProtocols.SSL_v2_HELLO);
860         }
861         if ((supportedProtocolsPacked & SSL_V2) != 0) {
862             protocols.add(SslProtocols.SSL_v2);
863         }
864         if ((supportedProtocolsPacked & SSL_V3) != 0) {
865             protocols.add(SslProtocols.SSL_v3);
866         }
867         if ((supportedProtocolsPacked & TLS_V1) != 0) {
868             protocols.add(SslProtocols.TLS_v1);
869         }
870         if ((supportedProtocolsPacked & TLS_V1_1) != 0) {
871             protocols.add(SslProtocols.TLS_v1_1);
872         }
873         if ((supportedProtocolsPacked & TLS_V1_2) != 0) {
874             protocols.add(SslProtocols.TLS_v1_2);
875         }
876         if ((supportedProtocolsPacked & TLS_V1_3) != 0) {
877             protocols.add(SslProtocols.TLS_v1_3);
878         }
879         return protocols;
880     }
881 
882     static boolean isBoringSSL() {
883         return IS_BORINGSSL;
884     }
885 
886     static boolean isAWSLC() {
887         return IS_AWSLC;
888     }
889 }