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.core5.annotation.Contract;
42 import org.apache.hc.core5.annotation.ThreadingBehavior;
43 import org.apache.hc.core5.http.HttpHost;
44 import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
45 import org.apache.hc.core5.http.ssl.TLS;
46 import org.apache.hc.core5.http.ssl.TlsCiphers;
47 import org.apache.hc.core5.http2.HttpVersionPolicy;
48 import org.apache.hc.core5.http2.ssl.ApplicationProtocol;
49 import org.apache.hc.core5.http2.ssl.H2TlsSupport;
50 import org.apache.hc.core5.net.NamedEndpoint;
51 import org.apache.hc.core5.reactor.ssl.SSLBufferMode;
52 import org.apache.hc.core5.reactor.ssl.SSLSessionInitializer;
53 import org.apache.hc.core5.reactor.ssl.SSLSessionVerifier;
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 @Override
89 public boolean upgrade(
90 final TransportSecurityLayer tlsSession,
91 final HttpHost host,
92 final SocketAddress localAddress,
93 final SocketAddress remoteAddress,
94 final Object attachment,
95 final Timeout handshakeTimeout) {
96 tlsSession.startTls(sslContext, host, sslBufferManagement, new SSLSessionInitializer() {
97
98 @Override
99 public void initialize(final NamedEndpoint endpoint, final SSLEngine sslEngine) {
100
101 final HttpVersionPolicy versionPolicy = attachment instanceof HttpVersionPolicy ?
102 (HttpVersionPolicy) attachment : HttpVersionPolicy.NEGOTIATE;
103
104 final SSLParameters sslParameters = sslEngine.getSSLParameters();
105 if (supportedProtocols != null) {
106 sslParameters.setProtocols(supportedProtocols);
107 } else if (versionPolicy != HttpVersionPolicy.FORCE_HTTP_1) {
108 sslParameters.setProtocols(TLS.excludeWeak(sslParameters.getProtocols()));
109 }
110 if (supportedCipherSuites != null) {
111 sslParameters.setCipherSuites(supportedCipherSuites);
112 } else if (versionPolicy == HttpVersionPolicy.FORCE_HTTP_2) {
113 sslParameters.setCipherSuites(TlsCiphers.excludeH2Blacklisted(sslParameters.getCipherSuites()));
114 }
115
116 if (versionPolicy != HttpVersionPolicy.FORCE_HTTP_1) {
117 H2TlsSupport.setEnableRetransmissions(sslParameters, false);
118 }
119
120 applyParameters(sslEngine, sslParameters, H2TlsSupport.selectApplicationProtocols(attachment));
121
122 initializeEngine(sslEngine);
123
124 if (LOG.isDebugEnabled()) {
125 LOG.debug("Enabled protocols: {}", Arrays.asList(sslEngine.getEnabledProtocols()));
126 LOG.debug("Enabled cipher suites:{}", Arrays.asList(sslEngine.getEnabledCipherSuites()));
127 }
128 }
129
130 }, new SSLSessionVerifier() {
131
132 @Override
133 public TlsDetails verify(final NamedEndpoint endpoint, final SSLEngine sslEngine) throws SSLException {
134 verifySession(host.getHostName(), sslEngine.getSession());
135 final TlsDetails tlsDetails = createTlsDetails(sslEngine);
136 final String negotiatedCipherSuite = sslEngine.getSession().getCipherSuite();
137 if (tlsDetails != null && ApplicationProtocol.HTTP_2.id.equals(tlsDetails.getApplicationProtocol())) {
138 if (TlsCiphers.isH2Blacklisted(negotiatedCipherSuite)) {
139 throw new SSLHandshakeException("Cipher suite `" + negotiatedCipherSuite
140 + "` does not provide adequate security for HTTP/2");
141 }
142 }
143 return tlsDetails;
144 }
145
146 }, handshakeTimeout);
147 return true;
148 }
149
150 abstract void applyParameters(SSLEngine sslEngine, SSLParameters sslParameters, String[] appProtocols);
151
152 abstract TlsDetails createTlsDetails(SSLEngine sslEngine);
153
154 protected void initializeEngine(final SSLEngine sslEngine) {
155 }
156
157 protected void verifySession(
158 final String hostname,
159 final SSLSession sslsession) throws SSLException {
160 tlsSessionValidator.verifySession(hostname, sslsession, hostnameVerifier);
161 }
162
163 }