public static SslContext createSslContext(
            Supplier<SslContextBuilder> builderSupplier, boolean forceHttp1,
            TlsEngineType tlsEngineType, boolean tlsAllowUnsafeCiphers,
            @Nullable Consumer<? super SslContextBuilder> userCustomizer,
            @Nullable List<X509Certificate> keyCertChainCaptor) {

        return MinifiedBouncyCastleProvider.call(() -> {
            final SslContextBuilder builder = builderSupplier.get();
            final SslProvider provider = tlsEngineType.sslProvider();
            builder.sslProvider(provider);

            final Set<String> supportedProtocols = supportedProtocols(builder);
            final List<String> protocols = DEFAULT_PROTOCOLS.stream()
                                                            .filter(supportedProtocols::contains)
                                                            .collect(toImmutableList());
            if (protocols.isEmpty()) {
                throw new IllegalStateException(provider + " supports none of " + DEFAULT_PROTOCOLS);
            }

            if (!warnedUnsupportedProtocols && DEFAULT_PROTOCOLS.size() != protocols.size()) {
                warnedUnsupportedProtocols = true;
                if (logger.isDebugEnabled()) {
                    final List<String> missingProtocols = DEFAULT_PROTOCOLS.stream()
                                                                           .filter(p -> !protocols.contains(p))
                                                                           .collect(toImmutableList());
                    logger.debug("{} does not support: {}", provider, missingProtocols);
                }
            }

            builder.protocols(protocols.toArray(EmptyArrays.EMPTY_STRINGS))
                   .ciphers(DEFAULT_CIPHERS, SupportedCipherSuiteFilter.INSTANCE);

            if (userCustomizer != null) {
                userCustomizer.accept(builder);
            }

            // We called user customization logic before setting ALPN to make sure they don't break
            // compatibility with HTTP/2.
            if (!forceHttp1) {
                builder.applicationProtocolConfig(ALPN_CONFIG);
            }
            maybeCaptureKeyCertChain(builder, keyCertChainCaptor);

            SslContext sslContext = null;
            boolean success = false;
            try {
                sslContext = builder.build();

                final Set<String> ciphers = ImmutableSet.copyOf(sslContext.cipherSuites());
                checkState(!ciphers.isEmpty(),
                           "SSLContext has no cipher suites enabled. " +
                           "You must specify at least one cipher suite.");

                if (forceHttp1) {
                    // Skip validation
                } else {
                    validateHttp2Ciphers(ciphers, tlsAllowUnsafeCiphers);
                }

                success = true;
                return sslContext;
            } catch (SSLException e) {
                throw new IllegalStateException(
                        "Could not initialize SSL context. Ensure that netty-tcnative is " +
                        "on the path, this is running on Java 11+, or user customization " +
                        "of the SSL context is supported by the environment.", e);
            } finally {
                if (!success && sslContext != null) {
                    ReferenceCountUtil.release(sslContext);
                }
            }
        });
    }
Creates a {@link SslContext} with Armeria's defaults, enabling support for HTTP/2,
TLSv1.3 (if supported), and TLSv1.2.
core/src/main/java/com/linecorp/armeria/internal/common/util/SslContextUtil.java