1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.handler.ssl;
17
18 import io.netty.internal.tcnative.Library;
19 import io.netty.internal.tcnative.SSL;
20 import io.netty.internal.tcnative.SSLContext;
21 import io.netty5.buffer.api.DefaultBufferAllocators;
22 import io.netty5.util.CharsetUtil;
23 import io.netty5.util.internal.EmptyArrays;
24 import io.netty5.util.internal.NativeLibraryLoader;
25 import io.netty5.util.internal.PlatformDependent;
26 import io.netty5.util.internal.SilentDispose;
27 import io.netty5.util.internal.StringUtil;
28 import io.netty5.util.internal.SystemPropertyUtil;
29 import io.netty5.util.internal.logging.InternalLogger;
30 import io.netty5.util.internal.logging.InternalLoggerFactory;
31
32 import java.io.ByteArrayInputStream;
33 import java.security.cert.CertificateException;
34 import java.security.cert.X509Certificate;
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.Collections;
38 import java.util.HashSet;
39 import java.util.LinkedHashSet;
40 import java.util.List;
41 import java.util.Set;
42
43 import static io.netty5.handler.ssl.SslUtils.DEFAULT_CIPHER_SUITES;
44 import static io.netty5.handler.ssl.SslUtils.TLSV13_CIPHERS;
45 import static io.netty5.handler.ssl.SslUtils.TLSV13_CIPHER_SUITES;
46 import static io.netty5.handler.ssl.SslUtils.addIfSupported;
47 import static io.netty5.handler.ssl.SslUtils.isTLSv13Cipher;
48 import static io.netty5.handler.ssl.SslUtils.useFallbackCiphersIfDefaultIsEmpty;
49
50
51
52
53
54 public final class OpenSsl {
55
56 private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSsl.class);
57 private static final Throwable UNAVAILABILITY_CAUSE;
58
59 static final List<String> DEFAULT_CIPHERS;
60 static final Set<String> AVAILABLE_CIPHER_SUITES;
61 private static final Set<String> AVAILABLE_OPENSSL_CIPHER_SUITES;
62 private static final Set<String> AVAILABLE_JAVA_CIPHER_SUITES;
63 private static final boolean SUPPORTS_KEYMANAGER_FACTORY;
64 private static final boolean SUPPORTS_OCSP;
65 private static final boolean TLSV13_SUPPORTED;
66 private static final boolean IS_BORINGSSL;
67 static final Set<String> SUPPORTED_PROTOCOLS_SET;
68 static final String[] EXTRA_SUPPORTED_TLS_1_3_CIPHERS;
69 static final String EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING;
70 static final String[] NAMED_GROUPS;
71
72
73
74
75 private static final String[] DEFAULT_NAMED_GROUPS = { "x25519", "secp256r1", "secp384r1", "secp521r1" };
76
77
78 private static final String CERT = "-----BEGIN CERTIFICATE-----\n" +
79 "MIICrjCCAZagAwIBAgIIdSvQPv1QAZQwDQYJKoZIhvcNAQELBQAwFjEUMBIGA1UEAxMLZXhhbXBs\n" +
80 "ZS5jb20wIBcNMTgwNDA2MjIwNjU5WhgPOTk5OTEyMzEyMzU5NTlaMBYxFDASBgNVBAMTC2V4YW1w\n" +
81 "bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAggbWsmDQ6zNzRZ5AW8E3eoGl\n" +
82 "qWvOBDb5Fs1oBRrVQHuYmVAoaqwDzXYJ0LOwa293AgWEQ1jpcbZ2hpoYQzqEZBTLnFhMrhRFlH6K\n" +
83 "bJND8Y33kZ/iSVBBDuGbdSbJShlM+4WwQ9IAso4MZ4vW3S1iv5fGGpLgbtXRmBf/RU8omN0Gijlv\n" +
84 "WlLWHWijLN8xQtySFuBQ7ssW8RcKAary3pUm6UUQB+Co6lnfti0Tzag8PgjhAJq2Z3wbsGRnP2YS\n" +
85 "vYoaK6qzmHXRYlp/PxrjBAZAmkLJs4YTm/XFF+fkeYx4i9zqHbyone5yerRibsHaXZWLnUL+rFoe\n" +
86 "MdKvr0VS3sGmhQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQADQi441pKmXf9FvUV5EHU4v8nJT9Iq\n" +
87 "yqwsKwXnr7AsUlDGHBD7jGrjAXnG5rGxuNKBQ35wRxJATKrUtyaquFUL6H8O6aGQehiFTk6zmPbe\n" +
88 "12Gu44vqqTgIUxnv3JQJiox8S2hMxsSddpeCmSdvmalvD6WG4NthH6B9ZaBEiep1+0s0RUaBYn73\n" +
89 "I7CCUaAtbjfR6pcJjrFk5ei7uwdQZFSJtkP2z8r7zfeANJddAKFlkaMWn7u+OIVuB4XPooWicObk\n" +
90 "NAHFtP65bocUYnDpTVdiyvn8DdqyZ/EO8n1bBKBzuSLplk2msW4pdgaFgY7Vw/0wzcFXfUXmL1uy\n" +
91 "G8sQD/wx\n" +
92 "-----END CERTIFICATE-----";
93
94 private static final String KEY = "-----BEGIN PRIVATE KEY-----\n" +
95 "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCCBtayYNDrM3NFnkBbwTd6gaWp\n" +
96 "a84ENvkWzWgFGtVAe5iZUChqrAPNdgnQs7Brb3cCBYRDWOlxtnaGmhhDOoRkFMucWEyuFEWUfops\n" +
97 "k0PxjfeRn+JJUEEO4Zt1JslKGUz7hbBD0gCyjgxni9bdLWK/l8YakuBu1dGYF/9FTyiY3QaKOW9a\n" +
98 "UtYdaKMs3zFC3JIW4FDuyxbxFwoBqvLelSbpRRAH4KjqWd+2LRPNqDw+COEAmrZnfBuwZGc/ZhK9\n" +
99 "ihorqrOYddFiWn8/GuMEBkCaQsmzhhOb9cUX5+R5jHiL3OodvKid7nJ6tGJuwdpdlYudQv6sWh4x\n" +
100 "0q+vRVLewaaFAgMBAAECggEAP8tPJvFtTxhNJAkCloHz0D0vpDHqQBMgntlkgayqmBqLwhyb18pR\n" +
101 "i0qwgh7HHc7wWqOOQuSqlEnrWRrdcI6TSe8R/sErzfTQNoznKWIPYcI/hskk4sdnQ//Yn9/Jvnsv\n" +
102 "U/BBjOTJxtD+sQbhAl80JcA3R+5sArURQkfzzHOL/YMqzAsn5hTzp7HZCxUqBk3KaHRxV7NefeOE\n" +
103 "xlZuWSmxYWfbFIs4kx19/1t7h8CHQWezw+G60G2VBtSBBxDnhBWvqG6R/wpzJ3nEhPLLY9T+XIHe\n" +
104 "ipzdMOOOUZorfIg7M+pyYPji+ZIZxIpY5OjrOzXHciAjRtr5Y7l99K1CG1LguQKBgQDrQfIMxxtZ\n" +
105 "vxU/1cRmUV9l7pt5bjV5R6byXq178LxPKVYNjdZ840Q0/OpZEVqaT1xKVi35ohP1QfNjxPLlHD+K\n" +
106 "iDAR9z6zkwjIrbwPCnb5kuXy4lpwPcmmmkva25fI7qlpHtbcuQdoBdCfr/KkKaUCMPyY89LCXgEw\n" +
107 "5KTDj64UywKBgQCNfbO+eZLGzhiHhtNJurresCsIGWlInv322gL8CSfBMYl6eNfUTZvUDdFhPISL\n" +
108 "UljKWzXDrjw0ujFSPR0XhUGtiq89H+HUTuPPYv25gVXO+HTgBFZEPl4PpA+BUsSVZy0NddneyqLk\n" +
109 "42Wey9omY9Q8WsdNQS5cbUvy0uG6WFoX7wKBgQDZ1jpW8pa0x2bZsQsm4vo+3G5CRnZlUp+XlWt2\n" +
110 "dDcp5dC0xD1zbs1dc0NcLeGDOTDv9FSl7hok42iHXXq8AygjEm/QcuwwQ1nC2HxmQP5holAiUs4D\n" +
111 "WHM8PWs3wFYPzE459EBoKTxeaeP/uWAn+he8q7d5uWvSZlEcANs/6e77eQKBgD21Ar0hfFfj7mK8\n" +
112 "9E0FeRZBsqK3omkfnhcYgZC11Xa2SgT1yvs2Va2n0RcdM5kncr3eBZav2GYOhhAdwyBM55XuE/sO\n" +
113 "eokDVutNeuZ6d5fqV96TRaRBpvgfTvvRwxZ9hvKF4Vz+9wfn/JvCwANaKmegF6ejs7pvmF3whq2k\n" +
114 "drZVAoGAX5YxQ5XMTD0QbMAl7/6qp6S58xNoVdfCkmkj1ZLKaHKIjS/benkKGlySVQVPexPfnkZx\n" +
115 "p/Vv9yyphBoudiTBS9Uog66ueLYZqpgxlM/6OhYg86Gm3U2ycvMxYjBM1NFiyze21AqAhI+HX+Ot\n" +
116 "mraV2/guSgDgZAhukRZzeQ2RucI=\n" +
117 "-----END PRIVATE KEY-----";
118
119 static {
120 Throwable cause = null;
121
122 if (SystemPropertyUtil.getBoolean("io.netty5.handler.ssl.noOpenSsl", false)) {
123 cause = new UnsupportedOperationException(
124 "OpenSSL was explicit disabled with -Dio.netty5.handler.ssl.noOpenSsl=true");
125
126 logger.debug(
127 "netty-tcnative explicit disabled; " +
128 OpenSslEngine.class.getSimpleName() + " will be unavailable.", cause);
129 } else {
130
131 try {
132 Class.forName("io.netty.internal.tcnative.SSLContext", false,
133 PlatformDependent.getClassLoader(OpenSsl.class));
134 } catch (ClassNotFoundException t) {
135 cause = t;
136 logger.debug(
137 "netty-tcnative not in the classpath; " +
138 OpenSslEngine.class.getSimpleName() + " will be unavailable.");
139 }
140
141
142 if (cause == null) {
143 try {
144
145 loadTcNative();
146 } catch (Throwable t) {
147 cause = t;
148 logger.debug(
149 "Failed to load netty-tcnative; " +
150 OpenSslEngine.class.getSimpleName() + " will be unavailable, unless the " +
151 "application has already loaded the symbols by some other means. " +
152 "See https://netty.io/wiki/forked-tomcat-native.html for more information.", t);
153 }
154
155 try {
156 String engine = SystemPropertyUtil.get("io.netty5.handler.ssl.openssl.engine", null);
157 if (engine == null) {
158 logger.debug("Initialize netty-tcnative using engine: 'default'");
159 } else {
160 logger.debug("Initialize netty-tcnative using engine: '{}'", engine);
161 }
162 initializeTcNative(engine);
163
164
165
166
167 cause = null;
168 } catch (Throwable t) {
169 if (cause == null) {
170 cause = t;
171 }
172 logger.debug(
173 "Failed to initialize netty-tcnative; " +
174 OpenSslEngine.class.getSimpleName() + " will be unavailable. " +
175 "See https://netty.io/wiki/forked-tomcat-native.html for more information.", t);
176 }
177 }
178 }
179
180 UNAVAILABILITY_CAUSE = cause;
181
182 if (cause == null) {
183 logger.debug("netty-tcnative using native library: {}", SSL.versionString());
184
185 final List<String> defaultCiphers = new ArrayList<>();
186 final Set<String> availableOpenSslCipherSuites = new LinkedHashSet<>(128);
187 boolean supportsKeyManagerFactory = false;
188 boolean tlsv13Supported = false;
189 String[] namedGroups = DEFAULT_NAMED_GROUPS;
190 String[] defaultConvertedNamedGroups = new String[namedGroups.length];
191 for (int i = 0; i < namedGroups.length; i++) {
192 defaultConvertedNamedGroups[i] = GroupsConverter.toOpenSsl(namedGroups[i]);
193 }
194
195 IS_BORINGSSL = "BoringSSL".equals(versionString());
196 if (IS_BORINGSSL) {
197 EXTRA_SUPPORTED_TLS_1_3_CIPHERS = new String [] { "TLS_AES_128_GCM_SHA256",
198 "TLS_AES_256_GCM_SHA384" ,
199 "TLS_CHACHA20_POLY1305_SHA256" };
200
201 StringBuilder ciphersBuilder = new StringBuilder(128);
202 for (String cipher: EXTRA_SUPPORTED_TLS_1_3_CIPHERS) {
203 ciphersBuilder.append(cipher).append(':');
204 }
205 ciphersBuilder.setLength(ciphersBuilder.length() - 1);
206 EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING = ciphersBuilder.toString();
207 } else {
208 EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS;
209 EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING = StringUtil.EMPTY_STRING;
210 }
211
212 try {
213 final long sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_ALL, SSL.SSL_MODE_SERVER);
214 long certBio = 0;
215 long keyBio = 0;
216 long cert = 0;
217 long key = 0;
218 try {
219
220
221 if (SslProvider.isTlsv13Supported(SslProvider.JDK)) {
222 try {
223 StringBuilder tlsv13Ciphers = new StringBuilder();
224
225 for (String cipher : TLSV13_CIPHERS) {
226 String converted = CipherSuiteConverter.toOpenSsl(cipher, IS_BORINGSSL);
227 if (converted != null) {
228 tlsv13Ciphers.append(converted).append(':');
229 }
230 }
231 if (tlsv13Ciphers.length() == 0) {
232 tlsv13Supported = false;
233 } else {
234 tlsv13Ciphers.setLength(tlsv13Ciphers.length() - 1);
235 SSLContext.setCipherSuite(sslCtx, tlsv13Ciphers.toString(), true);
236 tlsv13Supported = true;
237 }
238
239 } catch (Exception ignore) {
240 tlsv13Supported = false;
241 }
242 }
243
244 SSLContext.setCipherSuite(sslCtx, "ALL", false);
245
246 final long ssl = SSL.newSSL(sslCtx, true);
247 try {
248 for (String c: SSL.getCiphers(ssl)) {
249
250 if (c == null || c.isEmpty() || availableOpenSslCipherSuites.contains(c) ||
251
252 !tlsv13Supported && isTLSv13Cipher(c)) {
253 continue;
254 }
255 availableOpenSslCipherSuites.add(c);
256 }
257 if (IS_BORINGSSL) {
258
259
260 Collections.addAll(availableOpenSslCipherSuites, EXTRA_SUPPORTED_TLS_1_3_CIPHERS);
261 Collections.addAll(availableOpenSslCipherSuites,
262 "AEAD-AES128-GCM-SHA256",
263 "AEAD-AES256-GCM-SHA384",
264 "AEAD-CHACHA20-POLY1305-SHA256");
265 }
266
267 try (PemEncoded privateKey = PemPrivateKey.valueOf(KEY.getBytes(CharsetUtil.US_ASCII))) {
268
269
270 SSLContext.setCertificateCallback(sslCtx, null);
271
272 X509Certificate certificate = selfSignedCertificate();
273 certBio = ReferenceCountedOpenSslContext.toBIO(
274 DefaultBufferAllocators.offHeapAllocator(), certificate);
275 cert = SSL.parseX509Chain(certBio);
276
277 keyBio = ReferenceCountedOpenSslContext.toBIO(
278 DefaultBufferAllocators.offHeapAllocator(), privateKey);
279 key = SSL.parsePrivateKey(keyBio, null);
280
281 SSL.setKeyMaterial(ssl, cert, key);
282 supportsKeyManagerFactory = true;
283 } catch (Error ignore) {
284 logger.debug("KeyManagerFactory not supported.");
285 }
286 } finally {
287 SSL.freeSSL(ssl);
288 if (certBio != 0) {
289 SSL.freeBIO(certBio);
290 }
291 if (keyBio != 0) {
292 SSL.freeBIO(keyBio);
293 }
294 if (cert != 0) {
295 SSL.freeX509Chain(cert);
296 }
297 if (key != 0) {
298 SSL.freePrivateKey(key);
299 }
300 }
301
302 String groups = SystemPropertyUtil.get("jdk.tls.namedGroups", null);
303 if (groups != null) {
304 String[] nGroups = groups.split(",");
305 Set<String> supportedNamedGroups = new LinkedHashSet<>(nGroups.length);
306 Set<String> supportedConvertedNamedGroups = new LinkedHashSet<>(nGroups.length);
307
308 Set<String> unsupportedNamedGroups = new LinkedHashSet<>();
309 for (String namedGroup : nGroups) {
310 String converted = GroupsConverter.toOpenSsl(namedGroup);
311 if (SSLContext.setCurvesList(sslCtx, converted)) {
312 supportedConvertedNamedGroups.add(converted);
313 supportedNamedGroups.add(namedGroup);
314 } else {
315 unsupportedNamedGroups.add(namedGroup);
316 }
317 }
318
319 if (supportedNamedGroups.isEmpty()) {
320 namedGroups = defaultConvertedNamedGroups;
321 logger.info("All configured namedGroups are not supported: {}. Use default: {}.",
322 Arrays.toString(unsupportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS)),
323 Arrays.toString(DEFAULT_NAMED_GROUPS));
324 } else {
325 String[] groupArray = supportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS);
326 if (unsupportedNamedGroups.isEmpty()) {
327 logger.info("Using configured namedGroups -D 'jdk.tls.namedGroup': {} ",
328 Arrays.toString(groupArray));
329 } else {
330 logger.info("Using supported configured namedGroups: {}. Unsupported namedGroups: {}. ",
331 Arrays.toString(groupArray),
332 Arrays.toString(unsupportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS)));
333 }
334 namedGroups = supportedConvertedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS);
335 }
336 } else {
337 namedGroups = defaultConvertedNamedGroups;
338 }
339 } finally {
340 SSLContext.free(sslCtx);
341 }
342 } catch (Exception e) {
343 logger.warn("Failed to get the list of available OpenSSL cipher suites.", e);
344 }
345 NAMED_GROUPS = namedGroups;
346 AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.unmodifiableSet(availableOpenSslCipherSuites);
347 final Set<String> availableJavaCipherSuites = new LinkedHashSet<>(
348 AVAILABLE_OPENSSL_CIPHER_SUITES.size() * 2);
349 for (String cipher: AVAILABLE_OPENSSL_CIPHER_SUITES) {
350
351 if (!isTLSv13Cipher(cipher)) {
352 availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "TLS"));
353 availableJavaCipherSuites.add(CipherSuiteConverter.toJava(cipher, "SSL"));
354 } else {
355
356 availableJavaCipherSuites.add(cipher);
357 }
358 }
359
360 addIfSupported(availableJavaCipherSuites, defaultCiphers, DEFAULT_CIPHER_SUITES);
361 addIfSupported(availableJavaCipherSuites, defaultCiphers, TLSV13_CIPHER_SUITES);
362
363 addIfSupported(availableJavaCipherSuites, defaultCiphers, EXTRA_SUPPORTED_TLS_1_3_CIPHERS);
364
365 useFallbackCiphersIfDefaultIsEmpty(defaultCiphers, availableJavaCipherSuites);
366 DEFAULT_CIPHERS = Collections.unmodifiableList(defaultCiphers);
367
368 AVAILABLE_JAVA_CIPHER_SUITES = Collections.unmodifiableSet(availableJavaCipherSuites);
369
370 final Set<String> availableCipherSuites = new LinkedHashSet<>(
371 AVAILABLE_OPENSSL_CIPHER_SUITES.size() + AVAILABLE_JAVA_CIPHER_SUITES.size());
372 availableCipherSuites.addAll(AVAILABLE_OPENSSL_CIPHER_SUITES);
373 availableCipherSuites.addAll(AVAILABLE_JAVA_CIPHER_SUITES);
374
375 AVAILABLE_CIPHER_SUITES = availableCipherSuites;
376 SUPPORTS_KEYMANAGER_FACTORY = supportsKeyManagerFactory;
377
378 Set<String> protocols = new LinkedHashSet<>(6);
379
380 protocols.add(SslProtocols.SSL_v2_HELLO);
381 if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV2, SSL.SSL_OP_NO_SSLv2)) {
382 protocols.add(SslProtocols.SSL_v2);
383 }
384 if (doesSupportProtocol(SSL.SSL_PROTOCOL_SSLV3, SSL.SSL_OP_NO_SSLv3)) {
385 protocols.add(SslProtocols.SSL_v3);
386 }
387 if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1, SSL.SSL_OP_NO_TLSv1)) {
388 protocols.add(SslProtocols.TLS_v1);
389 }
390 if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_1, SSL.SSL_OP_NO_TLSv1_1)) {
391 protocols.add(SslProtocols.TLS_v1_1);
392 }
393 if (doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_OP_NO_TLSv1_2)) {
394 protocols.add(SslProtocols.TLS_v1_2);
395 }
396
397
398 if (tlsv13Supported && doesSupportProtocol(SSL.SSL_PROTOCOL_TLSV1_3, SSL.SSL_OP_NO_TLSv1_3)) {
399 protocols.add(SslProtocols.TLS_v1_3);
400 TLSV13_SUPPORTED = true;
401 } else {
402 TLSV13_SUPPORTED = false;
403 }
404
405 SUPPORTED_PROTOCOLS_SET = Collections.unmodifiableSet(protocols);
406 SUPPORTS_OCSP = doesSupportOcsp();
407
408 if (logger.isDebugEnabled()) {
409 logger.debug("Supported protocols (OpenSSL): {} ", SUPPORTED_PROTOCOLS_SET);
410 logger.debug("Default cipher suites (OpenSSL): {}", DEFAULT_CIPHERS);
411 }
412 } else {
413 DEFAULT_CIPHERS = Collections.emptyList();
414 AVAILABLE_OPENSSL_CIPHER_SUITES = Collections.emptySet();
415 AVAILABLE_JAVA_CIPHER_SUITES = Collections.emptySet();
416 AVAILABLE_CIPHER_SUITES = Collections.emptySet();
417 SUPPORTS_KEYMANAGER_FACTORY = false;
418 SUPPORTED_PROTOCOLS_SET = Collections.emptySet();
419 SUPPORTS_OCSP = false;
420 TLSV13_SUPPORTED = false;
421 IS_BORINGSSL = false;
422 EXTRA_SUPPORTED_TLS_1_3_CIPHERS = EmptyArrays.EMPTY_STRINGS;
423 EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING = StringUtil.EMPTY_STRING;
424 NAMED_GROUPS = DEFAULT_NAMED_GROUPS;
425 }
426 }
427
428 static String checkTls13Ciphers(InternalLogger logger, String ciphers) {
429 if (IS_BORINGSSL && !ciphers.isEmpty()) {
430 assert EXTRA_SUPPORTED_TLS_1_3_CIPHERS.length > 0;
431 Set<String> boringsslTlsv13Ciphers = new HashSet<>(EXTRA_SUPPORTED_TLS_1_3_CIPHERS.length);
432 Collections.addAll(boringsslTlsv13Ciphers, EXTRA_SUPPORTED_TLS_1_3_CIPHERS);
433 boolean ciphersNotMatch = false;
434 for (String cipher: ciphers.split(":")) {
435 if (boringsslTlsv13Ciphers.isEmpty()) {
436 ciphersNotMatch = true;
437 break;
438 }
439 if (!boringsslTlsv13Ciphers.remove(cipher) &&
440 !boringsslTlsv13Ciphers.remove(CipherSuiteConverter.toJava(cipher, "TLS"))) {
441 ciphersNotMatch = true;
442 break;
443 }
444 }
445
446
447 ciphersNotMatch |= !boringsslTlsv13Ciphers.isEmpty();
448
449 if (ciphersNotMatch) {
450 if (logger.isInfoEnabled()) {
451 StringBuilder javaCiphers = new StringBuilder(128);
452 for (String cipher : ciphers.split(":")) {
453 javaCiphers.append(CipherSuiteConverter.toJava(cipher, "TLS")).append(':');
454 }
455 javaCiphers.setLength(javaCiphers.length() - 1);
456 logger.info(
457 "BoringSSL doesn't allow to enable or disable TLSv1.3 ciphers explicitly." +
458 " Provided TLSv1.3 ciphers: '{}', default TLSv1.3 ciphers that will be used: '{}'.",
459 javaCiphers, EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING);
460 }
461 return EXTRA_SUPPORTED_TLS_1_3_CIPHERS_STRING;
462 }
463 }
464 return ciphers;
465 }
466
467 static boolean isSessionCacheSupported() {
468 return version() >= 0x10100000L;
469 }
470
471
472
473
474 static X509Certificate selfSignedCertificate() throws CertificateException {
475 return (X509Certificate) SslContext.X509_CERT_FACTORY.generateCertificate(
476 new ByteArrayInputStream(CERT.getBytes(CharsetUtil.US_ASCII))
477 );
478 }
479
480 private static boolean doesSupportOcsp() {
481 boolean supportsOcsp = false;
482 if (version() >= 0x10002000L) {
483 long sslCtx = -1;
484 try {
485 sslCtx = SSLContext.make(SSL.SSL_PROTOCOL_TLSV1_2, SSL.SSL_MODE_SERVER);
486 SSLContext.enableOcsp(sslCtx, false);
487 supportsOcsp = true;
488 } catch (Exception ignore) {
489
490 } finally {
491 if (sslCtx != -1) {
492 SSLContext.free(sslCtx);
493 }
494 }
495 }
496 return supportsOcsp;
497 }
498 private static boolean doesSupportProtocol(int protocol, int opt) {
499 if (opt == 0) {
500
501 return false;
502 }
503 long sslCtx = -1;
504 try {
505 sslCtx = SSLContext.make(protocol, SSL.SSL_MODE_COMBINED);
506 return true;
507 } catch (Exception ignore) {
508 return false;
509 } finally {
510 if (sslCtx != -1) {
511 SSLContext.free(sslCtx);
512 }
513 }
514 }
515
516
517
518
519
520
521 public static boolean isAvailable() {
522 return UNAVAILABILITY_CAUSE == null;
523 }
524
525
526
527
528
529
530
531 @Deprecated
532 public static boolean isAlpnSupported() {
533 return version() >= 0x10002000L;
534 }
535
536
537
538
539 public static boolean isOcspSupported() {
540 return SUPPORTS_OCSP;
541 }
542
543
544
545
546
547 public static int version() {
548 return isAvailable() ? SSL.version() : -1;
549 }
550
551
552
553
554
555 public static String versionString() {
556 return isAvailable() ? SSL.versionString() : null;
557 }
558
559
560
561
562
563
564
565 public static void ensureAvailability() {
566 if (UNAVAILABILITY_CAUSE != null) {
567 throw (Error) new UnsatisfiedLinkError(
568 "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE);
569 }
570 }
571
572
573
574
575
576
577
578 public static Throwable unavailabilityCause() {
579 return UNAVAILABILITY_CAUSE;
580 }
581
582
583
584
585 @Deprecated
586 public static Set<String> availableCipherSuites() {
587 return availableOpenSslCipherSuites();
588 }
589
590
591
592
593
594 public static Set<String> availableOpenSslCipherSuites() {
595 return AVAILABLE_OPENSSL_CIPHER_SUITES;
596 }
597
598
599
600
601
602 public static Set<String> availableJavaCipherSuites() {
603 return AVAILABLE_JAVA_CIPHER_SUITES;
604 }
605
606
607
608
609
610 public static boolean isCipherSuiteAvailable(String cipherSuite) {
611 String converted = CipherSuiteConverter.toOpenSsl(cipherSuite, IS_BORINGSSL);
612 if (converted != null) {
613 cipherSuite = converted;
614 }
615 return AVAILABLE_OPENSSL_CIPHER_SUITES.contains(cipherSuite);
616 }
617
618
619
620
621 public static boolean supportsKeyManagerFactory() {
622 return SUPPORTS_KEYMANAGER_FACTORY;
623 }
624
625
626
627
628
629
630
631 @Deprecated
632 public static boolean supportsHostnameValidation() {
633 return isAvailable();
634 }
635
636 private OpenSsl() { }
637
638 private static void loadTcNative() throws Exception {
639 String os = PlatformDependent.normalizedOs();
640 String arch = PlatformDependent.normalizedArch();
641
642 Set<String> libNames = new LinkedHashSet<>(5);
643 String staticLibName = "netty_tcnative";
644
645
646
647 if ("linux".equals(os)) {
648 Set<String> classifiers = PlatformDependent.normalizedLinuxClassifiers();
649 for (String classifier : classifiers) {
650 libNames.add(staticLibName + '_' + os + '_' + arch + '_' + classifier);
651 }
652
653 libNames.add(staticLibName + '_' + os + '_' + arch);
654
655
656
657
658 libNames.add(staticLibName + '_' + os + '_' + arch + "_fedora");
659 } else {
660 libNames.add(staticLibName + '_' + os + '_' + arch);
661 }
662 libNames.add(staticLibName + '_' + arch);
663 libNames.add(staticLibName);
664
665 NativeLibraryLoader.loadFirstAvailable(PlatformDependent.getClassLoader(SSLContext.class),
666 libNames.toArray(EmptyArrays.EMPTY_STRINGS));
667 }
668
669 private static boolean initializeTcNative(String engine) throws Exception {
670 return Library.initialize("provided", engine);
671 }
672
673 static void releaseIfNeeded(Object obj) {
674 SilentDispose.trySilentDispose(obj, logger);
675 }
676
677 static boolean isTlsv13Supported() {
678 return TLSV13_SUPPORTED;
679 }
680
681 static boolean isBoringSSL() {
682 return IS_BORINGSSL;
683 }
684 }