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