1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.client5.http.ssl;
29
30 import java.net.SocketAddress;
31 import java.util.Arrays;
32
33 import javax.net.ssl.HostnameVerifier;
34 import javax.net.ssl.SSLContext;
35 import javax.net.ssl.SSLEngine;
36 import javax.net.ssl.SSLException;
37 import javax.net.ssl.SSLHandshakeException;
38 import javax.net.ssl.SSLParameters;
39 import javax.net.ssl.SSLSession;
40
41 import org.apache.hc.client5.http.config.TlsConfig;
42 import org.apache.hc.core5.annotation.Contract;
43 import org.apache.hc.core5.annotation.ThreadingBehavior;
44 import org.apache.hc.core5.concurrent.FutureCallback;
45 import org.apache.hc.core5.http.HttpHost;
46 import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
47 import org.apache.hc.core5.http.ssl.TLS;
48 import org.apache.hc.core5.http.ssl.TlsCiphers;
49 import org.apache.hc.core5.http2.HttpVersionPolicy;
50 import org.apache.hc.core5.http2.ssl.ApplicationProtocol;
51 import org.apache.hc.core5.http2.ssl.H2TlsSupport;
52 import org.apache.hc.core5.net.NamedEndpoint;
53 import org.apache.hc.core5.reactor.ssl.SSLBufferMode;
54 import org.apache.hc.core5.reactor.ssl.TlsDetails;
55 import org.apache.hc.core5.reactor.ssl.TransportSecurityLayer;
56 import org.apache.hc.core5.util.Args;
57 import org.apache.hc.core5.util.Timeout;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61 @Contract(threading = ThreadingBehavior.STATELESS)
62 abstract class AbstractClientTlsStrategy implements TlsStrategy {
63
64 private static final Logger LOG = LoggerFactory.getLogger(AbstractClientTlsStrategy.class);
65
66 private final SSLContext sslContext;
67 private final String[] supportedProtocols;
68 private final String[] supportedCipherSuites;
69 private final SSLBufferMode sslBufferManagement;
70 private final HostnameVerifier hostnameVerifier;
71 private final TlsSessionValidator tlsSessionValidator;
72
73 AbstractClientTlsStrategy(
74 final SSLContext sslContext,
75 final String[] supportedProtocols,
76 final String[] supportedCipherSuites,
77 final SSLBufferMode sslBufferManagement,
78 final HostnameVerifier hostnameVerifier) {
79 super();
80 this.sslContext = Args.notNull(sslContext, "SSL context");
81 this.supportedProtocols = supportedProtocols;
82 this.supportedCipherSuites = supportedCipherSuites;
83 this.sslBufferManagement = sslBufferManagement != null ? sslBufferManagement : SSLBufferMode.STATIC;
84 this.hostnameVerifier = hostnameVerifier != null ? hostnameVerifier : HttpsSupport.getDefaultHostnameVerifier();
85 this.tlsSessionValidator = new TlsSessionValidator(LOG);
86 }
87
88
89
90
91 @Deprecated
92 @Override
93 public boolean upgrade(
94 final TransportSecurityLayer tlsSession,
95 final HttpHost host,
96 final SocketAddress localAddress,
97 final SocketAddress remoteAddress,
98 final Object attachment,
99 final Timeout handshakeTimeout) {
100 upgrade(tlsSession, host, attachment, handshakeTimeout, null);
101 return true;
102 }
103
104 @Override
105 public void upgrade(
106 final TransportSecurityLayer tlsSession,
107 final NamedEndpoint endpoint,
108 final Object attachment,
109 final Timeout handshakeTimeout,
110 final FutureCallback<TransportSecurityLayer> callback) {
111 tlsSession.startTls(sslContext, endpoint, sslBufferManagement, (e, sslEngine) -> {
112
113 final TlsConfig tlsConfig = attachment instanceof TlsConfig ? (TlsConfig) attachment : TlsConfig.DEFAULT;
114 final HttpVersionPolicy versionPolicy = tlsConfig.getHttpVersionPolicy();
115
116 final SSLParameters sslParameters = sslEngine.getSSLParameters();
117 final String[] supportedProtocols = tlsConfig.getSupportedProtocols();
118 if (supportedProtocols != null) {
119 sslParameters.setProtocols(supportedProtocols);
120 } else if (this.supportedProtocols != null) {
121 sslParameters.setProtocols(this.supportedProtocols);
122 } else if (versionPolicy != HttpVersionPolicy.FORCE_HTTP_1) {
123 sslParameters.setProtocols(TLS.excludeWeak(sslParameters.getProtocols()));
124 }
125 final String[] supportedCipherSuites = tlsConfig.getSupportedCipherSuites();
126 if (supportedCipherSuites != null) {
127 sslParameters.setCipherSuites(supportedCipherSuites);
128 } else if (this.supportedCipherSuites != null) {
129 sslParameters.setCipherSuites(this.supportedCipherSuites);
130 } else if (versionPolicy == HttpVersionPolicy.FORCE_HTTP_2) {
131 sslParameters.setCipherSuites(TlsCiphers.excludeH2Blacklisted(sslParameters.getCipherSuites()));
132 }
133
134 if (versionPolicy != HttpVersionPolicy.FORCE_HTTP_1) {
135 H2TlsSupport.setEnableRetransmissions(sslParameters, false);
136 }
137
138 applyParameters(sslEngine, sslParameters, H2TlsSupport.selectApplicationProtocols(versionPolicy));
139
140 initializeEngine(sslEngine);
141
142 if (LOG.isDebugEnabled()) {
143 LOG.debug("Enabled protocols: {}", Arrays.asList(sslEngine.getEnabledProtocols()));
144 LOG.debug("Enabled cipher suites:{}", Arrays.asList(sslEngine.getEnabledCipherSuites()));
145 LOG.debug("Starting handshake ({})", handshakeTimeout);
146 }
147 }, (e, sslEngine) -> {
148 verifySession(endpoint.getHostName(), sslEngine.getSession());
149 final TlsDetails tlsDetails = createTlsDetails(sslEngine);
150 final String negotiatedCipherSuite = sslEngine.getSession().getCipherSuite();
151 if (tlsDetails != null && ApplicationProtocol.HTTP_2.id.equals(tlsDetails.getApplicationProtocol())) {
152 if (TlsCiphers.isH2Blacklisted(negotiatedCipherSuite)) {
153 throw new SSLHandshakeException("Cipher suite `" + negotiatedCipherSuite
154 + "` does not provide adequate security for HTTP/2");
155 }
156 }
157 return tlsDetails;
158 }, handshakeTimeout, callback);
159 }
160
161 abstract void applyParameters(SSLEngine sslEngine, SSLParameters sslParameters, String[] appProtocols);
162
163 abstract TlsDetails createTlsDetails(SSLEngine sslEngine);
164
165 protected void initializeEngine(final SSLEngine sslEngine) {
166 }
167
168 protected void verifySession(
169 final String hostname,
170 final SSLSession sslsession) throws SSLException {
171 tlsSessionValidator.verifySession(hostname, sslsession, hostnameVerifier);
172 }
173
174 }