简体   繁体   English

使用 jdk8 进行 Conscrypt 为 http2 启用 ALPN

[英]Conscrypt with jdk8 to enable ALPN for http2

I have been searching how to implement Conscrypt SSL provider using conscrypt-openjdk-uber-1.4.1.jar for jdk8 to support ALPN for making a http2(using apache httpclient 5) connection to a server as jdk8 does not support ALPN by default or the other solution is to migrate to jdk9(or higher) which is not feasible for now as our product is heavily dependent on jdk8我一直在搜索如何使用conscrypt-openjdk-uber-1.4.1.jar for jdk8 实现Conscrypt SSL 提供程序以支持ALPN以建立与服务器的http2(使用 apache httpclient 5)连接,因为jdk8 默认不支持 ALPN或另一种解决方案是迁移到 jdk9(或更高版本),这暂时不可行,因为我们的产品严重依赖 jdk8

I have been searching extensively for some docs or examples to implement but I could not find one.我一直在广泛搜索一些要实现的文档或示例,但找不到。

I have tried to insert conscrypt provider as default and my program takes it as default provider but still it fails to connect with http2 server, my example is as follows,我尝试将 conscrypt 提供程序作为默认值插入,我的程序将其作为默认提供程序,但仍然无法与 http2 服务器连接,我的示例如下,

public static void main(final String[] args) throws Exception {
    Security.insertProviderAt(new OpenSSLProvider(), 1);
    final SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(new TrustAllStrategy()).build();
    final PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create().setTlsStrategy(new H2TlsStrategy(sslContext, NoopHostnameVerifier.INSTANCE)).build();
    final IOReactorConfig ioReactorConfig = IOReactorConfig.custom().setSoTimeout(Timeout.ofSeconds(5)).build();
    final MinimalHttpAsyncClient client = HttpAsyncClients.createMinimal(HttpVersionPolicy.FORCE_HTTP_2, H2Config.DEFAULT, null, ioReactorConfig, connectionManager);

    client.start();
    final HttpHost target = new HttpHost("localhost", 8082, "https");
    final Future<AsyncClientEndpoint> leaseFuture = client.lease(target, null);
    final AsyncClientEndpoint endpoint = leaseFuture.get(10, TimeUnit.SECONDS);
    try {
        String[] requestUris = new String[] {"/"};
        CountDownLatch latch = new CountDownLatch(requestUris.length);
        for (final String requestUri: requestUris) {
            SimpleHttpRequest request = SimpleHttpRequest.get(target, requestUri);
            endpoint.execute(SimpleRequestProducer.create(request), SimpleResponseConsumer.create(), new FutureCallback<SimpleHttpResponse>() {
                        @Override
                        public void completed(final SimpleHttpResponse response) {
                            latch.countDown();
                            System.out.println(requestUri + "->" + response.getCode());
                            System.out.println(response.getBody());
                        }

                        @Override
                        public void failed(final Exception ex) {
                            latch.countDown();
                            System.out.println(requestUri + "->" + ex);
                            ex.printStackTrace();
                        }

                        @Override
                        public void cancelled() {
                            latch.countDown();
                            System.out.println(requestUri + " cancelled");
                        }

                    });
        }
        latch.await();
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        endpoint.releaseAndReuse();
    }

    client.shutdown(ShutdownType.GRACEFUL);
}

this programs gives the output as这个程序给出的输出为

org.apache.hc.core5.http.ConnectionClosedException: Connection closed org.apache.hc.core5.http.ConnectionClosedException: Connection closed at org.apache.hc.core5.http2.impl.nio.FrameInputBuffer.read(FrameInputBuffer.java:146) at org.apache.hc.core5.http2.impl.nio.AbstractHttp2StreamMultiplexer.onInput(AbstractHttp2StreamMultiplexer.java:415) at org.apache.hc.core5.http2.impl.nio.AbstractHttp2IOEventHandler.inputReady(AbstractHttp2IOEventHandler.java:63) at org.apache.hc.core5.http2.impl.nio.ClientHttp2IOEventHandler.inputReady(ClientHttp2IOEventHandler.java:38) at org.apache.hc.core5.reactor.InternalDataChannel.onIOEvent(InternalDataChannel.java:117) at org.apache.hc.core5.reactor.InternalChannel.handleIOEvent(InternalChannel.java:50) at org.apache.hc.core5.reactor.SingleCoreIOReactor.processEvents(SingleCoreIOReactor.java:173) at org.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:123) at org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(A org.apache.hc.core5.http.ConnectionClosedException:连接关闭 org.apache.hc.core5.http.ConnectionClosedException:连接在 org.apache.hc.core5.http2.impl.nio.FrameInputBuffer.read(FrameInputBuffer.java) 关闭:146) 在 org.apache.hc.core5.http2.impl.nio.AbstractHttp2StreamMultiplexer.onInput(AbstractHttp2StreamMultiplexer.java:415) 在 org.apache.hc.core5.http2.impl.nio.AbstractHttp2IOEventHandler.inputReady(AbstractHttp2IOEventHandler.java:415) :63) 在 org.apache.hc.core5.http2.impl.nio.ClientHttp2IOEventHandler.inputReady(ClientHttp2IOEventHandler.java:38) 在 org.apache.hc.core5.reactor.InternalDataChannel.onIOEvent(InternalDataChannel.java:117) 在org.apache.hc.core5.reactor.InternalChannel.handleIOEvent(InternalChannel.java:50) 在 org.apache.hc.core5.reactor.SingleCoreIOReactor.processEvents(SingleCoreIOReactor.java:173) 在 org.apache.hc.core5。 reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:123) 在 org.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(A bstractSingleCoreIOReactor.java:80) at org.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44) at java.lang.Thread.run(Thread.java:748) bstractSingleCoreIOReactor.java:80) 在 org.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44) 在 java.lang.Thread.run(Thread.java:748)

If I print the provider and version it prints as Conscrypt version 1.0 and JDK 1.8.0_162 , but still it fails to connect with a http2 endpoint如果我打印提供程序和版本,它会打印为Conscrypt version 1.0JDK 1.8.0_162 ,但它仍然无法与 http2 端点连接

same chunk of code works perfectly if I connect using jdk9 with default provider, what I m missing here in conscrypt configuration?如果我使用带有默认提供程序的 jdk9 连接,相同的代码块可以完美运行,我在 conscrypt 配置中缺少什么?

Any help is appreciated任何帮助表示赞赏

Thanks in advance提前致谢

Just replacing the default JSSE provider with Conscrypt is not enough.仅用 Conscrypt 替换默认的 JSSE 提供程序是不够的。 One also needs a custom TlsStrategy that can take advantage of Conscrypt APIs.还需要一个可以利用 Conscrypt API 的自定义TlsStrategy

This what works for me with Java 1.8 and Conscrypt 1.4.1这对我来说适用于 Java 1.8 和 Conscrypt 1.4.1

static class ConscriptClientTlsStrategy implements TlsStrategy {

    private final SSLContext sslContext;

    public ConscriptClientTlsStrategy(final SSLContext sslContext) {
        this.sslContext = Args.notNull(sslContext, "SSL context");
    }

    @Override
    public boolean upgrade(
            final TransportSecurityLayer tlsSession,
            final HttpHost host,
            final SocketAddress localAddress,
            final SocketAddress remoteAddress,
            final Object attachment) {
        final String scheme = host != null ? host.getSchemeName() : null;
        if (URIScheme.HTTPS.same(scheme)) {
            tlsSession.startTls(
                    sslContext,
                    host,
                    SSLBufferMode.STATIC,
                    (endpoint, sslEngine) -> {
                        final SSLParameters sslParameters = sslEngine.getSSLParameters();
                        sslParameters.setProtocols(H2TlsSupport.excludeBlacklistedProtocols(sslParameters.getProtocols()));
                        sslParameters.setCipherSuites(H2TlsSupport.excludeBlacklistedCiphers(sslParameters.getCipherSuites()));
                        H2TlsSupport.setEnableRetransmissions(sslParameters, false);
                        final HttpVersionPolicy versionPolicy = attachment instanceof HttpVersionPolicy ?
                                (HttpVersionPolicy) attachment : HttpVersionPolicy.NEGOTIATE;
                        final String[] appProtocols;
                        switch (versionPolicy) {
                            case FORCE_HTTP_1:
                                appProtocols = new String[] { ApplicationProtocols.HTTP_1_1.id };
                                break;
                            case FORCE_HTTP_2:
                                appProtocols = new String[] { ApplicationProtocols.HTTP_2.id };
                                break;
                            default:
                                appProtocols = new String[] { ApplicationProtocols.HTTP_2.id, ApplicationProtocols.HTTP_1_1.id };
                        }
                        if (Conscrypt.isConscrypt(sslEngine)) {
                            sslEngine.setSSLParameters(sslParameters);
                            Conscrypt.setApplicationProtocols(sslEngine, appProtocols);
                        } else {
                            H2TlsSupport.setApplicationProtocols(sslParameters, appProtocols);
                            sslEngine.setSSLParameters(sslParameters);
                        }
                    },
                    (endpoint, sslEngine) -> {
                        if (Conscrypt.isConscrypt(sslEngine)) {
                            return new TlsDetails(sslEngine.getSession(), Conscrypt.getApplicationProtocol(sslEngine));
                        }
                        return null;
                    });
            return true;
        }
        return false;
    }

}

public static void main(String[] args) throws Exception {
    final SSLContext sslContext = SSLContexts.custom()
            .setProvider(Conscrypt.newProvider())
            .build();
    final PoolingAsyncClientConnectionManager cm = PoolingAsyncClientConnectionManagerBuilder.create()
            .setTlsStrategy(new ConscriptClientTlsStrategy(sslContext))
            .build();
    try (CloseableHttpAsyncClient client = HttpAsyncClients.custom()
            .setVersionPolicy(HttpVersionPolicy.NEGOTIATE)
            .setConnectionManager(cm)
            .build()) {

        client.start();

        final HttpHost target = new HttpHost("nghttp2.org", 443, "https");
        final String requestUri = "/httpbin";
        final HttpClientContext clientContext = HttpClientContext.create();

        final SimpleHttpRequest request = SimpleHttpRequests.GET.create(target, requestUri);
        final Future<SimpleHttpResponse> future = client.execute(
                SimpleRequestProducer.create(request),
                SimpleResponseConsumer.create(),
                clientContext,
                new FutureCallback<SimpleHttpResponse>() {

                    @Override
                    public void completed(final SimpleHttpResponse response) {
                        System.out.println(requestUri + "->" + response.getCode() + " " +
                                clientContext.getProtocolVersion());
                        System.out.println(response.getBody());
                        final SSLSession sslSession = clientContext.getSSLSession();
                        if (sslSession != null) {
                            System.out.println("SSL protocol " + sslSession.getProtocol());
                            System.out.println("SSL cipher suite " + sslSession.getCipherSuite());
                        }
                    }

                    @Override
                    public void failed(final Exception ex) {
                        System.out.println(requestUri + "->" + ex);
                    }

                    @Override
                    public void cancelled() {
                        System.out.println(requestUri + " cancelled");
                    }

                });
        future.get();

        System.out.println("Shutting down");
        client.shutdown(CloseMode.GRACEFUL);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM